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 eksplicitouter/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 fraawardwinner
), foretrækker jeg ikke at brugejoin
, men brugexists
ellerin
i stedet virker det mere logisk for mig.
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