sql >> Databasteknik >  >> RDS >> PostgreSQL

Hitta filmer med det högsta antalet utmärkelser under ett visst år - kodduplicering

Tja, du kan använda vanligt tabelluttryck för att undvika kodduplicering:

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)

eller så kan du göra något liknande med fönsterfunktion (otestat, men jag tror att PostgreSQL tillåter detta):

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

Ett annat sätt att göra detta kan vara att använda rank() funktion (otestad, kan vara att du måste använda två cte istället för en):

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

uppdatering När jag har skapat det här svaret var mitt huvudmål att visa hur man använder cte för att undvika kodduplicering. Generellt sett är det bättre att undvika att använda cte mer än en gång i fråga om det är möjligt - den första frågan använder 2 tabellsökning (eller indexsökning) och den andra och tredje använder bara en, så jag borde ange att det är bättre att gå med dessa frågor. Hur som helst, @Erwin gjorde detta test i sitt svar. Bara för att lägga till hans stora poänger:

  • Jag avråder också från natural join på grund av dettas felbenägenhet. Min huvudsakliga RDBMS är faktiskt SQL Server som inte stöder det så jag är mer van vid explicit outer/inner join .
  • Det är god vana att alltid använda alias i dina frågor, så att du kan undvika konstiga resultat .
  • Detta kan vara helt subjektivt, men vanligtvis om jag använder någon tabell enbart för att filtrera bort rader från huvudtabellen i frågan (som i den här frågan vill vi bara få awards för år 2012 och filtrera bara rader från awardwinner ), jag föredrar att inte använda join , men använd exists eller in istället verkar det mer logiskt för mig.
Så den sista frågan kan vara:
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. Kan inte använda LISTAGG

  2. Formatera delvis okända datum med DateTime() från en databas?

  3. Hur väljer man alla poster från en tabell som inte finns i en annan tabell?

  4. Problem med att binda en imploderad array till en mysql-förberedd sats