PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Znajdź filmy z największą liczbą nagród w danym roku — powielanie kodu

Cóż, możesz użyć wspólnego wyrażenia tabelowego aby uniknąć powielania kodu:

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)

lub możesz zrobić coś takiego za pomocą funkcji okna (nietestowane, ale myślę, że PostgreSQL na to pozwala):

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

Innym sposobem na to może być użycie rank() funkcja (nieprzetestowana, być może będziesz musiał użyć dwóch cte zamiast jednego):

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

aktualizacja Kiedy stworzyłem tę odpowiedź, moim głównym celem było pokazanie, jak używać cte, aby uniknąć duplikacji kodu. Ogólnie rzecz biorąc, lepiej unikać używania cte więcej niż jeden raz w zapytaniu, jeśli jest to możliwe - pierwsze zapytanie wykorzystuje skanowanie 2 tabel (lub wyszukiwanie indeksu), a drugie i trzecie używa tylko jednego, więc powinienem określić, że lepiej jest iść z te zapytania. W każdym razie @Erwin wykonał te testy w swojej odpowiedzi. Wystarczy dodać do jego wielkich głównych punktów:

  • Odradzam również natural join z powodu podatnej na błędy natury tego. Właściwie moim głównym RDBMS jest SQL Server, który go nie obsługuje, więc jestem bardziej przyzwyczajony do jawnego outer/inner join .
  • Dobrym zwyczajem jest używanie aliasów w zapytaniach, aby uniknąć dziwne wyniki .
  • Może to być rzecz całkowicie subiektywna, ale zwykle, jeśli używam jakiejś tabeli tylko do odfiltrowania wierszy z głównej tabeli zapytania (tak jak w tym zapytaniu, chcemy po prostu uzyskać awards dla roku 2012 i po prostu filtruj wiersze od awardwinner ), wolę nie używać join , ale użyj exists lub in zamiast tego wydaje mi się to bardziej logiczne.
Zatem końcowe zapytanie może wyglądać tak:
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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak zresetować sekwencję klawiszy podstawowych Postgres, gdy nie będzie ona zsynchronizowana?

  2. Jak skopiować strukturę jednej tabeli do drugiej z ograniczeniami klucza obcego w psql?

  3. Jak dokonać wyboru z klauzulą ​​array zawiera wartość w psql

  4. Jak wstawić wiele wartości jednocześnie do tabeli postgres?

  5. Błąd:musi być właścicielem bazy danych