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

Jaký je rozdíl mezi Postgres DISTINCT vs DISTINCT ON?

DISTINCT a DISTINCT ON mají zcela odlišnou sémantiku.

Nejdřív teorie

DISTINCT platí pro celou n-tici. Jakmile je výsledek dotazu vypočítán, DISTINCT odstraní z výsledku všechny duplicitní n-tice.

Předpokládejme například tabulku R s následujícím obsahem:

#table r;
a | b 
---+---
1 | a
2 | b
3 | c
3 | d
2 | e
1 | a

(6 řádků)

SELECT odlišné * od R bude mít za následek:

# select distinct * from r;
 a | b 
---+---
 1 | a
 3 | d
 2 | e
 2 | b
 3 | c
(5 rows)

Všimněte si, že odlišné platí pro celý seznam projektovaných atributů:takto

select distinct * from R

je sémanticky ekvivalentní k

select distinct a,b from R

Nemůžete vydat

select a, distinct b From R

DISTINCT musí následovat po SELECT. Vztahuje se na celou n-tici, nikoli na atribut výsledku.

DISTINCT ON je postgresql doplněk jazyka. Je podobný, ale ne identický, jako group by.

Jeho syntaxe je:

 SELECT DISTINCT ON (attributeList) <rest as any query>

Například:

 SELECT DISTINCT ON (a) * from R

Jeho sémantiku lze popsat následovně. Vypočítejte dotaz jako obvykle -- bez DISTINCT ON (a) --- ale před zobrazením výsledku seřaďte aktuální výsledek a seskupte jej podle seznamu atributů v DISTINCT ON (podobně jako group by). Nyní proveďte projekci pomocí první n-tice v každé skupině a ostatní n-tice ignorujte.

Příklad:

select distinct * from r order by a;
     a | b 
    ---+---
     1 | a
     2 | e
     2 | b
     3 | c
     3 | d
    (5 rows)

Potom pro každou jinou hodnotu a vezměte první n-tici. Což je stejné jako:

 SELECT DISTINCT on (a) * from r;
  a | b 
 ---+---
 1 | a
 2 | b
 3 | c
 (3 rows)

Některé DBMS (zejména sqlite) vám umožní spustit tento dotaz:

 SELECT a,b from R group by a;

A to vám dá podobný výsledek.

Postgresql povolí tento dotaz tehdy a pouze tehdy, pokud existuje funkční závislost od a do b. Jinými slovy, tento dotaz bude platný, pokud pro jakoukoli instanci vztahu R existuje pouze jedna jedinečná n-tice pro každou hodnotu nebo a (takže výběr první n-tice je deterministický:existuje pouze jedna n-tice).

Pokud je například primární klíč R a, pak a->b a:

SELECT a,b FROM R group by a

je totožné s:

  SELECT DISTINCT on (a) a, b from r;

A teď zpět k vašemu problému:

První dotaz:

SELECT DISTINCT count(dimension1)
FROM data_table;

vypočítá počet dimenze1 (počet n-tic v tabulce dat, kde dimenze1 není null). Tento dotaz vrací jednu n-tici, která je vždy jedinečná (proto DISTINCT je redundantní).

Dotaz 2:

SELECT count(*)
FROM (SELECT DISTINCT ON (dimension1) dimension1
FROM data_table
GROUP BY dimension1) AS tmp_table;

Toto je dotaz v dotazu. Dovolte mi to přepsat pro přehlednost:

WITH tmp_table AS (
   SELECT DISTINCT ON (dimension1) 
     dimension1 FROM data_table
     GROUP by dimension1) 
SELECT count(*) from tmp_table

Pojďme vypočítat první tmp_table. Jak jsem uvedl výše, nejprve ignorujme DISTINCT ON a proveďte zbytek dotazu. Toto je skupina podle dimenze1. Výsledkem této části dotazu bude tedy jedna n-tice na jinou hodnotu dimenze1.

Nyní, ROZDÍL ON. Opět používá dimenzi1. Ale dimenze1 je již jedinečná (kvůli skupině podle). Z toho vyplývá, že DISTINCT ON superflouos (nedělá nic). Konečný počet je jednoduše součtem všech n-tic ve skupině podle.

Jak vidíte, v následujícím dotazu je ekvivalence (platí pro jakýkoli vztah s atributem a):

SELECT (DISTINCT ON a) a
FROM R

a

SELECT a FROM R group by a

a

SELECT DISTINCT a FROM R

Upozornění

Použití výsledků DISTINCT ON v dotazu může být nedeterministické pro danou instanci databáze. Jinými slovy, dotaz může vracet různé výsledky pro stejné tabulky.

Jeden zajímavý aspekt

Distinct ON emuluje špatné chování sqlite mnohem čistším způsobem. Předpokládejme, že R má dva atributy a a b:

SELECT a, b FROM R group by a

je neplatný příkaz v SQL. Přesto běží na sqlite. Jednoduše vezme náhodnou hodnotu b z kterékoli z n-tic ve skupině stejných hodnot a. V Postgresql je tento příkaz nezákonný. Místo toho musíte použít DISTINCT ON a napsat:

SELECT DISTINCT ON (a) a,b from R

Důsledek

DISTINCT ON je užitečné ve skupině, když chcete získat přístup k hodnotě, která je funkčně závislá na skupině podle atributů. Jinými slovy, pokud víte, že pro každou skupinu atributů mají vždy stejnou hodnotu jako třetí atribut, použijte DISTINCT ON pro tuto skupinu atributů. Jinak byste museli vytvořit JOIN, abyste získali třetí atribut.



  1. Seznam prvků formátu Datetime v Oracle

  2. Sdílení databáze vs dělení na oddíly

  3. C#/Oracle:Zadat kódování/sadu znaků dotazu?

  4. Jak volat funkci s parametrem Rowtype z příkazu select v Oracle