sql >> Databáze >  >> RDS >> PostgreSQL

Najděte filmy s nejvyšším počtem ocenění v určitém roce - duplikace kódu

Můžete použít běžný tabulkový výraz abyste zabránili duplicitě kódu:

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)

nebo můžete něco takového udělat pomocí funkce okna (netestováno, ale myslím, že PostgreSQL to umožňuje):

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

Dalším způsobem, jak toho dosáhnout, může být použití rank() funkce (netestováno, možná budete muset použít dvě cte místo jednoho):

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

aktualizovat Když jsem vytvořil tuto odpověď, mým hlavním cílem bylo ukázat, jak používat cte, aby se zabránilo duplicitě kódu. Obecně je lepší vyhnout se použití cte více než jednou v dotazu, pokud je to možné - první dotaz používá 2 skenování tabulky (nebo hledání indexu) a druhý a třetí používá pouze jeden, takže bych měl uvést, že je lepší jít s tyto dotazy. Každopádně @Erwin provedl tyto testy ve své odpovědi. Jen abych dodal k jeho velkým hlavním bodům:

  • Také nedoporučuji natural join z důvodu náchylnosti k chybám. Ve skutečnosti je mým hlavním RDBMS SQL Server, který jej nepodporuje, takže jsem více zvyklý na explicitní outer/inner join .
  • Je dobrým zvykem ve svých dotazech vždy používat aliasy, takže se můžete vyhnout podivné výsledky .
  • To může být zcela subjektivní záležitost, ale obvykle, pokud nějakou tabulku používám pouze k odfiltrování řádků z hlavní tabulky dotazu (jako v tomto dotazu, chceme jen získat awards pro rok 2012 a stačí filtrovat řádky od awardwinner ), raději nepoužívám join , ale použijte exists nebo in místo toho mi to připadá logičtější.
Takže poslední dotaz by mohl znít:
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


  1. 4 Užitečné nástroje příkazového řádku pro sledování výkonu MySQL v Linuxu

  2. MYSQL:Spojte seznam hodnot do tabulky

  3. MySQL vyberte součet s hodnotami seskupit podle a prázdnými hodnotami

  4. Nainstalujte Postgres.app na Mac