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 explicitouter/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ånawardwinner
), jag föredrar att inte användajoin
, men användexists
ellerin
istället verkar det mer logiskt för 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