Cestujícího s nejdelším jménem ve skupině můžete pohodlně získat pomocí DISTINCT ON .
Ale nevidím žádný způsob, jak to zkombinovat (nebo jakýmkoli jiným jednoduchým způsobem) s vaším původním dotazem v jediném SELECT . Navrhuji spojit dva samostatné poddotazy:
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 v klauzuli spojení pohodlně vypíše pouze jednu instanci orig , takže můžete jednoduše použít SELECT * ve vnějším SELECT .
Pokud passenger může být NULL, je důležité přidat NULLS LAST :
Z několika jmen cestujících se stejnou maximální délkou ve stejné skupině získáte libovolnou volbu - pokud do ORDER BY nepřidáte další výrazy jako tiebreaker. Podrobné vysvětlení ve výše uvedené odpovědi.
Výkon?
Obvykle je lepší jedno skenování, zejména u sekvenčního skenování.
Výše uvedený dotaz používá dva skeny (možná indexové / pouze indexové skeny). Ale druhé skenování je poměrně levné, pokud tabulka není příliš velká, aby se vešla do mezipaměti (většinou). Lukas navrhl alternativní dotaz pouze s jediným SELECT
přidávání:
, (ARRAY_AGG (passenger ORDER BY LENGTH (passenger) DESC))[1] -- I'd add NULLS LAST
Nápad je to chytrý, ale když jsem testoval naposledy
, array_agg pomocí ORDER BY nepředvedl tak dobrý výkon. (Režie na skupinu ORDER BY je značný a manipulace s poli je také drahá.)
Stejný přístup může být levnější s vlastní agregační funkcí first() jako podle pokynů v Postgres Wiki zde
. Nebo ještě rychleji, s verzí napsanou v C, dostupnou na PGXN
. Eliminuje dodatečné náklady na manipulaci s poli, ale stále potřebujeme ORDER BY pro každou skupinu . Může být rychlejší jen pro několik skupin. Pak byste přidali:
, first(passenger ORDER BY length(passenger) DESC NULLS LAST)
Gordon
a Lukas
zmiňte také funkci okna first_value()
. Funkce okna se použijí po agregační funkce. Chcete-li jej použít ve stejném SELECT , museli bychom agregovat passenger nějak první - chytit 22. Gordon to řeší pomocí subdotazu - dalšího kandidáta na dobrý výkon se standardním Postgresem.
first() dělá totéž bez poddotazu a mělo by být jednodušší a o něco rychlejší. Stále to ale nebude rychlejší než samostatný DISTINCT ON ve většině případů s několika řádky na skupinu. Pro mnoho řádků na skupinu je rekurzivní technika CTE obvykle rychlejší. Existují ještě rychlejší techniky, pokud máte samostatnou tabulku obsahující všechny relevantní, jedinečné orig hodnoty. Podrobnosti:
Nejlepší řešení závisí na různých faktorech. Důkaz pudingu je v jídle. Chcete-li optimalizovat výkon, musíte otestovat své nastavení. Výše uvedený dotaz by měl patřit mezi nejrychlejší.