sql >> Database teknologi >  >> RDS >> PostgreSQL

Find film med det højeste antal priser i et bestemt år - kodeduplikering

Nå, du kan bruge fælles tabeludtryk for at undgå kodeduplikering:

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 du kan gøre sådan noget med vinduefunktion (Utestet, men jeg tror, ​​at PostgreSQL tillader dette):

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

En anden måde at gøre dette på kunne være at bruge rank() funktion (utestet, kan være du skal bruge to cte i stedet for 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

opdatering Da jeg har lavet dette svar, var mit hovedmål at vise, hvordan man bruger cte for at undgå kodeduplikering. Generelt er det bedre at undgå at bruge cte mere end én gang i forespørgslen, hvis det er muligt - første forespørgsel bruger 2 tabelscanning (eller indekssøgning) og anden og tredje bruger kun én, så jeg bør specificere, at det er bedre at gå med disse forespørgsler. Anyway, @Erwin lavede denne test i sit svar. Bare for at tilføje til hans store hovedpunkter:

  • Jeg fraråder også natural join på grund af denne fejlbehæftede karakter. Faktisk er mit primære RDBMS SQL Server, som ikke understøtter det, så jeg er mere vant til eksplicit outer/inner join .
  • Det er en god vane altid at bruge aliaser i dine forespørgsler, så du kan undgå mærkelige resultater .
  • Dette kunne være en fuldstændig subjektiv ting, men normalt, hvis jeg kun bruger en tabel til at bortfiltrere rækker fra hovedtabellen i forespørgslen (som i denne forespørgsel, vil vi bare gerne modtage awards for år 2012 og filtrer bare rækker fra awardwinner ), foretrækker jeg ikke at bruge join , men brug exists eller in i stedet virker det mere logisk for mig.
Så den sidste forespørgsel kunne være:
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. Sådan får du to_number til at ignorere ikke-numeriske værdier

  2. Sådan migrerer du SQL Server-job fra en SQL Server-instans til en anden

  3. Rekursiv forespørgsel i PostgreSQL. VÆLG *

  4. Flere afkrydsningsfelter gemt i et enkelt felt i en database