我正在尝试编写查询 (PostgreSQL) 以获取“2012 年获奖次数最多的电影”。
我有下表:
CREATE TABLE Award(
ID_AWARD bigserial CONSTRAINT Award_pk PRIMARY KEY,
award_name VARCHAR(90),
category VARCHAR(90),
award_year integer,
CONSTRAINT award_unique UNIQUE (award_name, category, award_year));
CREATE TABLE AwardWinner(
ID_AWARD integer,
ID_ACTOR integer,
ID_MOVIE integer,
CONSTRAINT AwardWinner_pk PRIMARY KEY (ID_AWARD));
我写了下面的查询,它给出了正确的结果,但我认为有很多代码重复。
select * from
(select id_movie, count(id_movie) as awards
from Award natural join awardwinner
where award_year = 2012 group by id_movie) as SUB
where awards = (select max(count) from
(select id_movie, count(id_movie)
from Award natural join awardwinner
where award_year = 2012 group by id_movie) as SUB2);
所以SUB
和SUB2
是完全相同的子查询。有更好的方法吗?
最佳答案
那么你可以使用 common table expression避免代码重复:
with cte_s as (
select id_movie, count(id_movie) as awards
from Award natural join awardwinner
where award_year = 2012
group by id_movie
)
select
sub.id_movie, sub.awards
from cte_s as sub
where sub.awards = (select max(sub2.awards) from cte_s as sub2)
或者你可以用 window function 做这样的事情(未经测试,但我认为 PostgreSQL 允许这样做):
with cte_s as (
select
id_movie,
count(id_movie) as awards,
max(count(id_movie)) over() as max_awards
from Award natural join awardwinner
where award_year = 2012
group by id_movie
)
select id_movie
from cte_s
where max_awards = awards
另一种方法是使用 rank()函数(未经测试,可能你必须使用两个 cte 而不是一个):
with cte_s as (
select
id_movie,
count(id_movie) as awards,
rank() over(order by count(id_movie) desc) as rnk
from Award natural join awardwinner
where award_year = 2012
group by id_movie
)
select id_movie
from cte_s
where rnk = 1
更新 当我创建这个答案时,我的主要目标是展示如何使用 cte 来避免代码重复。一般来说,如果可能的话,最好避免在查询中多次使用 cte - 第一次查询使用 2 表扫描(或索引查找),第二次和第三次只使用一次,所以我应该指定最好使用这些查询。无论如何,@Erwin 在他的回答中做了这个测试。只是为了补充他的主要观点:
- 我还建议不要使用
自然连接
,因为它容易出错。实际上,我的主要 RDBMS 是不支持它的 SQL Server,所以我更习惯于显式outer/inner join
。 - 在查询中始终使用别名是个好习惯,这样可以避免 strange results .
- 这可能是完全主观的事情,但通常如果我只使用一些表来从查询的主表中过滤掉行(就像在这个查询中,我们只想获得
awards
2012 年,只过滤来自awardwinner
的行),我不喜欢使用join
,而是使用exists
或in
相反,这对我来说似乎更合乎逻辑。
with cte_s as (
select
aw.id_movie,
count(*) as awards,
rank() over(order by count(*) desc) as rnk
from awardwinner as aw
where
exists (
select *
from award as a
where a.id_award = aw.id_award and a.award_year = 2012
)
group by aw.id_movie
)
select id_movie
from cte_s
where rnk = 1
关于sql - 查找某年获奖次数最多的电影——代码重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20021602/