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 esplicitareouter/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 daawardwinner
), preferisco non usarejoin
, ma usaexists
oin
invece, mi sembra più logico.
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