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

Użyj czegoś takiego jak TOP z GROUP BY

Możesz wygodnie pobrać pasażera z najdłuższym nazwiskiem w grupie za pomocą DISTINCT ON .

Ale nie widzę możliwości połączenia tego (lub innego prostego sposobu) z oryginalnym zapytaniem w jednym SELECT . Proponuję dołączyć do dwóch oddzielnych podzapytań:

SELECT *
FROM  (  -- your original query
   SELECT orig
        , count(*) AS flight_cnt
        , count(distinct passenger) AS pass_cnt
        , percentile_cont(0.5) WITHIN GROUP (ORDER BY bags) AS bag_cnt_med
   FROM   table1
   GROUP  BY orig
   ) org_query
JOIN  (  -- my addition
   SELECT DISTINCT ON (orig) orig, passenger AS pass_max_len_name
   FROM   table1
   ORDER  BY orig, length(passenger) DESC NULLS LAST
   ) pas USING (orig);

USING w klauzuli join wygodnie wyświetla tylko jedną instancję orig , więc możesz po prostu użyć SELECT * w zewnętrznym SELECT .

Jeśli passenger może być NULL, ważne jest, aby dodać NULLS LAST :

Spośród wielu nazwisk pasażerów o tej samej maksymalnej długości w tej samej grupie otrzymujesz dowolny wybór - chyba że dodasz więcej wyrażeń do ORDER BY jako rozstrzygający remisy. Szczegółowe wyjaśnienie w odpowiedzi, do której link znajduje się powyżej.

Wydajność?

Zazwyczaj pojedynczy skan jest lepszy, szczególnie w przypadku skanów sekwencyjnych.

Powyższe zapytanie używa dwóch skany (może skany indeksowe / tylko indeksowe). Ale drugi skan jest stosunkowo tani, chyba że tabela jest zbyt duża, aby zmieścić się w pamięci podręcznej (w większości). Lukas zasugerował alternatywne zapytanie z tylko jednym SELECT dodawanie:

, (ARRAY_AGG (passenger ORDER BY LENGTH (passenger) DESC))[1]  -- I'd add NULLS LAST

Pomysł jest sprytny, ale ostatni test , array_agg z ORDER BY nie działał tak dobrze. (Narzut na grupę ORDER BY jest znaczna, a obsługa tablic też jest droga.)

To samo podejście może być tańsze dzięki niestandardowej funkcji agregującej first() tak jak napisano na Postgres Wiki tutaj . Lub jeszcze szybciej, dzięki wersji napisanej w C, dostępnej na PGXN . Eliminuje dodatkowy koszt obsługi tablic, ale nadal potrzebujemy na grupę ORDER BY . Może być szybszy tylko dla kilku grup. Następnie dodałbyś:

 , first(passenger ORDER BY length(passenger) DESC NULLS LAST)

Gordon i Lukas wspomnij także o funkcji okna first_value() . Funkcje okna są stosowane po funkcje agregujące. Aby użyć go w tym samym SELECT , musielibyśmy zagregować passenger jakoś po pierwsze - złap 22. Gordon rozwiązuje to za pomocą podzapytania - kolejnego kandydata do dobrej wydajności ze standardowym Postgresem.

first() robi to samo bez podzapytania i powinien być prostszy i nieco szybszy. Ale nadal nie będzie szybszy niż oddzielne DISTINCT ON w większości przypadków z kilkoma rzędami na grupę. W przypadku wielu wierszy na grupę rekurencyjna technika CTE jest zwykle szybsza. Istnieją jeszcze szybsze techniki, jeśli masz osobną tabelę zawierającą wszystkie istotne, unikalne orig wartości. Szczegóły:

Najlepsze rozwiązanie zależy od różnych czynników. Dowodem na budyń jest jedzenie. Aby zoptymalizować wydajność, musisz przetestować swoją konfigurację. Powyższe zapytanie powinno być jednym z najszybszych.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL regexp_replace z dopasowanym wyrażeniem

  2. Policz liczbę nakładających się elementów w tablicy Postgres

  3. Jak Sinh() działa w PostgreSQL

  4. Jak wyszukać konkretną wartość we wszystkich tabelach (PostgreSQL)?

  5. Czy mogę użyć WYJĄTKÓW w PĘTLI FOR, aby wymusić kontynuację w przypadku błędu?