Du kan nemt hente passageren med det længste navn pr. gruppe med DISTINCT ON
.
Men jeg ser ingen måde at kombinere det (eller nogen anden simpel måde) med din oprindelige forespørgsel i en enkelt SELECT
. Jeg foreslår at forbinde to separate underforespørgsler:
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
i join-sætningen udsender bekvemt kun én forekomst af orig
, så du kan blot bruge SELECT *
i den ydre SELECT
.
Hvis passenger
kan være NULL, er det vigtigt at tilføje NULLS LAST
:
Fra flere passagernavne med samme maksimale længde i samme gruppe får du et vilkårligt valg - medmindre du tilføjer flere udtryk til ORDER BY
som tiebreaker. Detaljeret forklaring i svaret, der er linket ovenfor.
Ydeevne?
Typisk er en enkelt scanning overlegen, især med sekventielle scanninger.
Ovenstående forespørgsel bruger to scanninger (måske indeks-/indeksscanninger). Men den anden scanning er forholdsvis billig, medmindre bordet er for stort til at passe i cachen (for det meste). Lukas foreslog en alternativ forespørgsel med kun en enkelt SELECT
tilføjer:
, (ARRAY_AGG (passenger ORDER BY LENGTH (passenger) DESC))[1] -- I'd add NULLS LAST
Ideen er smart, men sidste gang jeg testede
, array_agg
med ORDER BY
ikke præsterede så godt. (Overhead for pr-gruppe ORDER BY
er betydelig, og array-håndtering er også dyr.)
Den samme tilgang kan være billigere med en tilpasset aggregeret funktion first()
som instrueret i Postgres Wiki her
. Eller endnu hurtigere med en version skrevet i C, tilgængelig på PGXN
. Eliminerer de ekstra omkostninger til array-håndtering, men vi har stadig brug for pr-gruppe ORDER BY
. Kan være hurtigere kun for få grupper. Du vil derefter tilføje:
, first(passenger ORDER BY length(passenger) DESC NULLS LAST)
Gordon
og Lukas
nævne også vinduesfunktionen first_value()
. Vinduesfunktioner anvendes efter aggregerede funktioner. For at bruge det i den samme SELECT
, skal vi samle passenger
på en eller anden måde først - catch 22. Gordon løser dette med en underforespørgsel - en anden kandidat til god præstation med standard Postgres.
first()
gør det samme uden underforespørgsel og burde være enklere og en smule hurtigere. Men det vil stadig ikke være hurtigere end en separat DISTINCT ON
for de fleste tilfælde med få rækker pr. gruppe. For mange rækker pr. gruppe er en rekursiv CTE-teknik typisk hurtigere. Der er endnu hurtigere teknikker, hvis du har en separat tabel, der indeholder alle relevante, unikke orig
værdier. Detaljer:
Den bedste løsning afhænger af forskellige faktorer. Beviset for buddingen er i spisningen. For at optimere ydeevnen skal du teste med din opsætning. Ovenstående forespørgsel burde være blandt de hurtigste.