PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Encontre filmes com maior número de prêmios em determinado ano - duplicação de código


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ícito outer/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 de awardwinner ), prefiro não usar join , mas use exists ou in em vez disso, parece mais lógico para mim.
Portanto, a consulta final pode ser:
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