Bem, você pode usar a expressão de tabela comum para evitar duplicação de código:
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 você pode fazer algo assim com função de janela (não testado, mas acho que o PostgreSQL permite isso):
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
Outra maneira de fazer isso pode ser usar rank() função (não testada, pode ser que você precise usar dois cte em vez de um):
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
atualizar Quando criei esta resposta, meu objetivo principal era mostrar como usar o cte para evitar a duplicação de código. Em geral, é melhor evitar o uso de cte mais de uma vez na consulta, se possível - a primeira consulta usa 2 varreduras de tabela (ou busca de índice) e a segunda e a terceira usam apenas uma, então devo especificar que é melhor ir com essas consultas. De qualquer forma, @Erwin fez esses testes em sua resposta. Apenas para adicionar aos seus grandes pontos principais:
- Também aconselho contra a
natural join
devido à natureza propensa a erros disso. Na verdade, meu principal RDBMS é o SQL Server, que não o suporta, então estou mais acostumado a explícitoouter/inner join
. - É um bom hábito sempre usar aliases em suas consultas, para evitar resultado estranho .
- Isso pode ser algo totalmente subjetivo, mas geralmente se eu estiver usando alguma tabela apenas para filtrar as linhas da tabela principal da consulta (como nesta consulta, queremos apenas obter
awards
para o ano de 2012 e apenas filtre as linhas deawardwinner
), prefiro não usarjoin
, mas useexists
ouin
em vez disso, parece mais lógico para mim.
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