Well you can use common table expression to avoid code duplication:
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)
or you can do something like this with window function (untested, but I think PostgreSQL allows this):
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
Another way to do this could be to use rank() function (untested, may be you have to use two cte instead of one):
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
update When I've created this answer, my main goal was to show how to use cte to avoid code duplication. In genearal, it's better to avoid using cte more than one time in query if it's possible - first query uses 2 table scan (or index seek) and second and third uses only one, so I've should specify that it's better to go with these queries. Anyway, @Erwin made this tests in his answer. Just to add to his great major points:
- I also advice against
natural join
because of error-prone nature of this. Actually, my main RDBMS is SQL Server which are not support it so I'm more used to explicit outer/inner join
.
- It's good habit to always use aliases in your queries, so you can avoid strange results.
- This could be totally subjective thing, but usually if I'm using some table only to filter out rows from main table of the query (like in this query, we just want to get
awards
for year 2012 and just filter rows from awardwinner
), I prefer not to use join
, but use exists
or in
instead, it seems more logical for me.
So final query could be:
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