以下已针对 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语句其余部分所需的所有详细信息,因此不需要JOINwith 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 thecategory_id fields (of which there will be two sharing the same value owing to the joining) and subsorted byfilm.length` 的记录。
选择字段后,每条记录的值category_id都会与 的值进行比较@currentCategory。如果它们不匹配,则@currentRecord初始化为1并@currentCategory更新为 的新值category_id。如果它们匹配,则@currentRecord递增。在任何一种情况下,分配给的值@currentRecord都会返回到SELECT给定别名的字段中的语句中recordNumber。因此,我们能够在我们精炼的数据集前面加上一个记录号。
然后剩下的就是SELECT精炼数据集中的所有记录(无记录号),其中记录号小于或等于5。
请注意,上面的结果没有使用任何相关的子查询,而是使用JOIN's to 表和子查询。
如果您有任何问题或意见,请随时发表相应的评论。