Eh bien, vous pouvez utiliser expression de table commune pour éviter la duplication de code :
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)
ou vous pouvez faire quelque chose comme ça avec fonction window (non testé, mais je pense que PostgreSQL le permet) :
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
Une autre façon de faire cela pourrait être d'utiliser rank() fonction (non testée, vous devrez peut-être utiliser deux cte au lieu d'un) :
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
mettre à jour Lorsque j'ai créé cette réponse, mon objectif principal était de montrer comment utiliser cte pour éviter la duplication de code. En général, il vaut mieux éviter d'utiliser cte plus d'une fois dans la requête si c'est possible - la première requête utilise 2 balayages de table (ou recherche d'index) et les deuxième et troisième n'en utilisent qu'un, donc je dois préciser qu'il vaut mieux aller avec ces requêtes. Quoi qu'il en soit, @Erwin a fait ces tests dans sa réponse. Juste pour ajouter à ses grands points majeurs :
- Je déconseille également la
natural join
en raison de la nature sujette aux erreurs de cela. En fait, mon SGBDR principal est SQL Server qui ne le prend pas en charge, donc je suis plus habitué à uneouter/inner join
explicite . - C'est une bonne habitude de toujours utiliser des alias dans vos requêtes, afin d'éviter résultats étranges .
- Cela pourrait être une chose totalement subjective, mais généralement si j'utilise une table uniquement pour filtrer les lignes de la table principale de la requête (comme dans cette requête, nous voulons juste obtenir des
awards
pour l'année 2012 et filtrez simplement les lignes deawardwinner
), je préfère ne pas utiliserjoin
, mais utilisezexists
ouin
au lieu de cela, cela me semble plus logique.
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