SELECT actor_id, COUNT(*) as cnt
FROM sakila.film_actor
GROUP BY actor_id
ORDER BY cnt DESC
LIMIT 10;
如果我们要获得相应的排名值的话,则可以引入变量来完成:
SET @curr_cnt := 0, @prev_cnt := 0, @rank := 0;
SELECT actor_id,
@curr_cnt := cnt AS cnt,
@rank := IF(@prev_cnt <> @curr_cnt, @rank+1, @rank) as rank,
@prev_cnt:= @curr_cnt AS dummy
FROM (
SELECT actor_id, COUNT(*) AS cnt
FROM sakila.film_actor
GROUP BY actor_id
ORDER BY cnt DESC
LIMIT 10
) as der;
SELECT id FROM users WHERE id = 123
UNION ALL
SELECT id FROM users_archived WHERE id = 123;
这个查询会先从当前正在使用的用户表查询 id 为123的用户,然后 在从已归档的用户表找同样 id 的用户。但是,这种写法比较低效,即便是在 users 表找到了想要找的用户,还是需要从users_archived 这个表再找一次,而实际用户 id 为123的只会存在其中的一张表中或两张表的数据是一样的。通过懒加载的联合查询,可以避免这种情况——只有在第一个分支没有找到数据时才进行第二个分支的查询。因此可以使用 MySQL 的 GREATEST 方法来作为查询结果的容器以避免多返回数据列。
SELECT GREATEST(@found := -1, id) AS id, users.name, 'users' as which_tb1
FROM users WHERE id = 123
UNION ALL
SELECT id, users_archived.name, 'users_archived'
FROM users_archived WHERE id = 123 AND @found IS NULL
UNION ALL
SELECT 1, '', 'reset' FROM DUAL WHERE ( @found := NULL) IS NOT NULL;
上述的查询如果第一行有结果,则@found 不会被赋值,因而是 NULL,从而执行第二次查询。而第三次的 UNION 实际没什么效果,只是为了将@found恢复到 NULL 值,以便这段 SQL 可以重复执行。另一个验证的方法是对同一张表进行这样的操作,可以发现实际只会返回一行数据或不返回数据(查询不到数据时)。
SELECT GREATEST(@found := -1, `id`) AS `id`, `infocenter_city`.`name`, 'city' as which_tb1
FROM `infocenter_city` WHERE `id` = 460100
UNION ALL
SELECT `id`, `infocenter_city`.`name`, 'infocenter_city'
FROM `infocenter_city` WHERE id = 460100 AND @found IS NULL
UNION ALL
SELECT 1, '', 'reset' FROM DUAL WHERE ( @found := NULL) IS NOT NULL