以下已针对 Sakila 数据库进行了测试(成功)...
SELECT title,
length,
categoryName
FROM ( SELECT CASE
WHEN film_category.category_id = @currentCategory THEN
@currentRecord := @currentRecord + 1
ELSE
@currentRecord := 1 AND
@currentCategory := film_category.category_id
END AS recordNumber,
film.title AS title,
film.length AS length,
categoryName AS categoryName
FROM film
JOIN film_category ON film.film_id = film_category.film_id
JOIN ( SELECT film_category.category_id AS category_id,
category.name AS categoryName,
AVG( film.length ) AS categoryAvgLength
FROM film
JOIN film_category ON film.film_id = film_category.film_id
JOIN category ON category.category_id = film_category.category_id
GROUP BY film_category.category_id,
category.name
) AS categoryAvgLengthFinder ON film_category.category_id = categoryAvgLengthFinder.category_id,
(
SELECT @currentCategory := 0 AS currentCategory
) AS currentValuesInitialiser
WHERE film.length > categoryAvgLength
ORDER BY film_category.category_id,
film.length
) AS allLarger
WHERE recordNumber <= 5;
该语句首先使用以下子查询形成一个“表”,其中包含每个category
的唯一标识符category_id
、该name
的category
和相应的平均值Film
length
...
SELECT film_category.category_id AS category_id,
category.name AS categoryName,
AVG( film.length ) AS categoryAvgLength
FROM film
JOIN film_category ON film.film_id = film_category.film_id
JOIN category ON category.category_id = film_category.category_id
GROUP BY film_category.category_id,
category.name
然后将这个子查询的结果连接到film
和film_catgory
。由于子查询从中检索category
语句其余部分所需的所有详细信息,因此不需要JOIN
with category
。
然后将生成的数据集交叉连接以在同一语句SELECT @currentCategory := 0 AS currentCategory
中初始化变量。@currentCategory
这确实是以将调用的字段附加到上面生成的数据集为代价的currentCategory
,因此您可能更喜欢使用以下代码...
SET @currentCategory := 0;
SELECT title,
length,
categoryName
FROM ( SELECT CASE
WHEN film_category.category_id = @currentCategory THEN
@currentRecord := @currentRecord + 1
ELSE
@currentRecord := 1 AND
@currentCategory := film_category.category_id
END AS recordNumber,
film.title AS title,
film.length AS length,
categoryName AS categoryName
FROM film
JOIN film_category ON film.film_id = film_category.film_id
JOIN ( SELECT film_category.category_id AS category_id,
category.name AS categoryName,
AVG( film.length ) AS categoryAvgLength
FROM film
JOIN film_category ON film.film_id = film_category.film_id
JOIN category ON category.category_id = film_category.category_id
GROUP BY film_category.category_id,
category.name
) AS categoryAvgLengthFinder ON film_category.category_id = categoryAvgLengthFinder.category_id
WHERE film.length > categoryAvgLength
ORDER BY film_category.category_id,
film.length
) AS allLarger
WHERE recordNumber <= 5;
一旦JOIN
's 被执行(并被@currentCategory
初始化),结果数据集将被细化为那些其值为film.length' is greater than the corresponding average for that category. The refined dataset is then sorted (not grouped) by one of the
category_id fields (of which there will be two sharing the same value owing to the joining) and subsorted by
film.length` 的记录。
选择字段后,每条记录的值category_id
都会与 的值进行比较@currentCategory
。如果它们不匹配,则@currentRecord
初始化为1
并@currentCategory
更新为 的新值category_id
。如果它们匹配,则@currentRecord
递增。在任何一种情况下,分配给的值@currentRecord
都会返回到SELECT
给定别名的字段中的语句中recordNumber
。因此,我们能够在我们精炼的数据集前面加上一个记录号。
然后剩下的就是SELECT
精炼数据集中的所有记录(无记录号),其中记录号小于或等于5
。
请注意,上面的结果没有使用任何相关的子查询,而是使用JOIN
's to 表和子查询。
如果您有任何问题或意见,请随时发表相应的评论。