Puoi comodamente recuperare il passeggero con il nome più lungo per gruppo con DISTINCT ON
.
Ma non vedo alcun modo per combinare questo (o qualsiasi altro modo semplice) con la tua query originale in un unico SELECT
. Suggerisco di unire due sottoquery separate:
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
nella clausola join convenientemente restituisce solo un'istanza di orig
, quindi puoi semplicemente usare SELECT *
nel SELECT
esterno .
Se passenger
può essere NULL, è importante aggiungere NULLS LAST
:
Da più nomi di passeggeri con la stessa lunghezza massima nello stesso gruppo, ottieni una scelta arbitraria - a meno che tu non aggiunga più espressioni a ORDER BY
come spareggio. Spiegazione dettagliata nella risposta collegata sopra.
Prestazioni?
In genere, una singola scansione è superiore, specialmente con le scansioni sequenziali.
La query precedente ne utilizza due scansioni (forse scansioni indice/solo indice). Ma la seconda scansione è relativamente economica a meno che la tabella non sia troppo grande per stare nella cache (per lo più). Lukas ha suggerito una query alternativa con un solo singolo SELECT
aggiungendo:
, (ARRAY_AGG (passenger ORDER BY LENGTH (passenger) DESC))[1] -- I'd add NULLS LAST
L'idea è intelligente, ma l'ultima volta che ho provato
, array_agg
con ORDER BY
non ha funzionato così bene. (Il sovraccarico di ORDER BY
per gruppo è sostanziale e anche la gestione dell'array è costosa.)
Lo stesso approccio può essere più economico con una funzione aggregata personalizzata first()
come indicato nel Wiki di Postgres qui
. Oppure, ancora più veloce, con una versione scritta in C, disponibile su PGXN
. Elimina il costo aggiuntivo per la gestione dell'array, ma abbiamo ancora bisogno di ORDER BY
per gruppo . Potrebbe essere più veloce solo per pochi gruppi. Dovresti quindi aggiungere:
, first(passenger ORDER BY length(passenger) DESC NULLS LAST)
Gordon
e Lukas
menziona anche la funzione finestra first_value()
. Le funzioni della finestra vengono applicate dopo funzioni aggregate. Per usarlo nello stesso SELECT
, dovremmo aggregare passenger
in qualche modo first - catch 22. Gordon risolve questo problema con una sottoquery, un altro candidato per buone prestazioni con Postgres standard.
first()
fa lo stesso senza subquery e dovrebbe essere più semplice e un po' più veloce. Ma non sarà comunque più veloce di un DISTINCT ON
separato per la maggior parte dei casi con poche righe per gruppo. Per molte righe per gruppo, una tecnica CTE ricorsiva è in genere più veloce. Esistono tecniche ancora più veloci se si dispone di una tabella separata che contiene tutti gli orig
pertinenti e univoci i valori. Dettagli:
La soluzione migliore dipende da vari fattori. La prova del budino è nel mangiarlo. Per ottimizzare le prestazioni devi testare con la tua configurazione. La query di cui sopra dovrebbe essere tra le più veloci.