sql >> Database >  >> RDS >> PostgreSQL

Wat is het verschil tussen Postgres DISTINCT en DISTINCT ON?

DISTINCT en DISTINCT ON hebben een totaal verschillende semantiek.

Eerst de theorie

DISTINCT is van toepassing op een hele tupel. Zodra het resultaat van de zoekopdracht is berekend, verwijdert DISTINCT eventuele dubbele tuples uit het resultaat.

Neem bijvoorbeeld een tabel R met de volgende inhoud:

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

(6 rijen)

SELECT onderscheiden * van R zal resulteren:

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

Merk op dat onderscheiden van toepassing is op de hele lijst met geprojecteerde attributen:dus

select distinct * from R

is semantisch gelijk aan

select distinct a,b from R

U kunt niet uitgeven

select a, distinct b From R

DISTINCT moet op SELECT volgen. Het is van toepassing op de hele tuple, niet op een attribuut van het resultaat.

DISTINCT ON is een postgresql-toevoeging aan de taal. Het is vergelijkbaar, maar niet identiek, om te groeperen op.

De syntaxis is:

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

Bijvoorbeeld:

 SELECT DISTINCT ON (a) * from R

De semantiek kan als volgt worden beschreven. Bereken de query zoals gewoonlijk -- zonder DISTINCT ON (a) --- maar sorteer vóór de projectie van het resultaat het huidige resultaat en groepeer het volgens de attributenlijst in DISTINCT ON (vergelijkbaar met groeperen op). Voer nu de projectie uit met de eerste tupel in elke groep en negeer de andere tupels.

Voorbeeld:

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

Neem dan voor elke verschillende waarde van a de eerste tuple. Wat hetzelfde is als:

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

Met sommige DBMS (met name sqlite) kunt u deze query uitvoeren:

 SELECT a,b from R group by a;

En dit geeft je een vergelijkbaar resultaat.

Postgresql staat deze query toe, als en alleen als er een functionele afhankelijkheid is van a naar b. Met andere woorden, deze query is geldig als er voor elke instantie van de relatie R slechts één unieke tuple is voor elke waarde of a (dus het selecteren van de eerste tuple is deterministisch:er is maar één tuple).

Als de primaire sleutel van R bijvoorbeeld a is, dan a->b en:

SELECT a,b FROM R group by a

is identiek aan:

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

Nu, terug naar uw probleem:

Eerste vraag:

SELECT DISTINCT count(dimension1)
FROM data_table;

berekent de telling van dimensie1 (aantal tupels in data_table waarbij dimensie1 niet nul is). Deze query retourneert één tuple, die altijd uniek is (vandaar DISTINCT is overbodig).

Vraag 2:

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

Dit is een query in een query. Laat me het voor de duidelijkheid herschrijven:

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

Laten we eerst tmp_table berekenen. Zoals ik hierboven al zei, laten we eerst de DISTINCT ON negeren en de rest van de query uitvoeren. Dit is een groepering op dimensie1. Vandaar dat dit deel van de zoekopdracht zal resulteren in één tuple per verschillende waarde van dimensie1.

Nu, de DISTINCT ON. Het gebruikt dimensie1 opnieuw. Maar dimensie1 is al uniek (vanwege de group by). Dit maakt de DISTINCT ON superflouos (het doet niets). De laatste telling is gewoon een telling van alle tuples in de groep door.

Zoals u kunt zien, is er een equivalentie in de volgende query (het is van toepassing op elke relatie met een attribuut a):

SELECT (DISTINCT ON a) a
FROM R

en

SELECT a FROM R group by a

en

SELECT DISTINCT a FROM R

Waarschuwing

Het gebruik van DISTINCT ON-resultaten in een query kan niet-deterministisch zijn voor een bepaalde instantie van de database. Met andere woorden, de query kan verschillende resultaten opleveren voor dezelfde tabellen.

Een interessant aspect

Distinct ON emuleert een slechte gedrag van sqlite op een veel schonere manier. Neem aan dat R twee attributen a en b heeft:

SELECT a, b FROM R group by a

is een illegale instructie in SQL. Toch draait het op sqlite. Het neemt gewoon een willekeurige waarde van b van een van de tuples in de groep met dezelfde waarden van a. In Postgresql is deze verklaring onwettig. In plaats daarvan moet u DISTINCT ON gebruiken en schrijven:

SELECT DISTINCT ON (a) a,b from R

Gevolg

DISTINCT ON is handig in een groep door wanneer u toegang wilt tot een waarde die functioneel afhankelijk is van de groep op attributen. Met andere woorden, als je weet dat voor elke groep attributen ze altijd dezelfde waarde hebben van het derde attribuut, gebruik dan DISTINCT ON die groep attributen. Anders zou je een JOIN moeten maken om dat derde attribuut op te halen.



  1. Query met SQL-datumintervallen

  2. Meerdere tabellen in PostgreSQL laten vallen met een jokerteken

  3. Mysql:opdracht uitvoeren geweigerd aan gebruiker ''@'localhost' voor routinefout

  4. SubSonic genereert geen MySql-tabellen met externe sleutels