sql >> Databáze >  >> RDS >> PostgreSQL

Použijte něco jako TOP s GROUP BY

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



  1. Rozdíly mezi MySQL a SQL Serverem

  2. Počet mysql počet shod regulárního výrazu na pole

  3. Chyba formuláře/databáze Django:hodnota je příliš dlouhá pro typový znak se liší (4)

  4. Neo4j - Odstranit vztah pomocí Cypher