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.