PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Trouvez les films avec le plus grand nombre de récompenses au cours d'une année donnée - duplication de code

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é à une outer/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 de awardwinner ), je préfère ne pas utiliser join , mais utilisez exists ou in au lieu de cela, cela me semble plus logique.
Ainsi, la requête finale pourrait être :
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