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ší.