PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Trova i film con il maggior numero di premi in un determinato anno:duplicazione del codice

Bene, puoi usare espressione di tabella comune per evitare la duplicazione del codice:

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)

oppure puoi fare qualcosa del genere con la funzione finestra (non testato, ma penso che PostgreSQL lo consenta):

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

Un altro modo per farlo potrebbe essere usare rank() funzione (non testata, potrebbe essere necessario utilizzare due cte invece di uno):

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

aggiornamento Quando ho creato questa risposta, il mio obiettivo principale era mostrare come utilizzare cte per evitare la duplicazione del codice. In generale, è meglio evitare di usare cte più di una volta nella query, se possibile:la prima query utilizza 2 scansioni di tabelle (o ricerca di indice) e la seconda e la terza ne usano solo una, quindi dovrei specificare che è meglio andare con queste domande. Ad ogni modo, @Erwin ha eseguito questi test nella sua risposta. Solo per aggiungere ai suoi grandi punti principali:

  • Sconsiglio anche natural join a causa della natura soggetta a errori di questo. In realtà, il mio RDBMS principale è SQL Server che non lo supporta, quindi sono più abituato a esplicitare outer/inner join .
  • È buona abitudine utilizzare sempre alias nelle query, quindi puoi evitare strani risultati .
  • Questa potrebbe essere una cosa totalmente soggettiva, ma di solito se sto usando una tabella solo per filtrare le righe dalla tabella principale della query (come in questa query, vogliamo solo ottenere awards per l'anno 2012 e filtra le righe da awardwinner ), preferisco non usare join , ma usa exists o in invece, mi sembra più logico.
Quindi la query finale potrebbe essere:
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