PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Finden Sie Filme mit der höchsten Anzahl an Auszeichnungen in einem bestimmten Jahr - Code-Duplizierung

Nun, Sie können den allgemeinen Tabellenausdruck verwenden Codeduplizierung zu vermeiden:

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)

oder Sie können so etwas mit der Fensterfunktion machen (ungetestet, aber ich denke, PostgreSQL erlaubt dies):

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

Eine andere Möglichkeit, dies zu tun, könnte die Verwendung von rank() Funktion (ungetestet, möglicherweise müssen Sie zwei cte anstelle von einem verwenden):

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

aktualisieren Als ich diese Antwort erstellt habe, war mein Hauptziel zu zeigen, wie man cte verwendet, um Codeduplizierung zu vermeiden. Im Allgemeinen ist es besser zu vermeiden, cte mehr als einmal in Abfragen zu verwenden, wenn dies möglich ist - die erste Abfrage verwendet 2 Tabellenscans (oder Indexsuchen) und die zweite und dritte verwendet nur eine, daher sollte ich angeben, dass es besser ist, mit zu gehen diese Abfragen. Wie auch immer, @Erwin hat diese Tests in seiner Antwort durchgeführt. Nur um seine großen Hauptpunkte hinzuzufügen:

  • Ich rate auch von natural join ab aufgrund der Fehleranfälligkeit dieser. Eigentlich ist mein Haupt-RDBMS SQL Server, die es nicht unterstützen, also bin ich eher an explizite outer/inner join gewöhnt .
  • Es ist eine gute Angewohnheit, in Ihren Abfragen immer Aliase zu verwenden, damit Sie seltsame Ergebnisse .
  • Dies könnte eine völlig subjektive Sache sein, aber normalerweise, wenn ich eine Tabelle nur verwende, um Zeilen aus der Haupttabelle der Abfrage herauszufiltern (wie in dieser Abfrage, wollen wir nur awards erhalten für das Jahr 2012 und filtern Sie einfach die Zeilen von awardwinner ), ziehe ich es vor, join nicht zu verwenden , aber verwenden Sie exists oder in stattdessen erscheint es mir logischer.
Die letzte Abfrage könnte also lauten:
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