sql >> Databasteknik >  >> RDS >> PostgreSQL

Vad är skillnaden mellan Postgres DISTINCT vs DISTINCT ON?

DISTINCT och DISTINCT ON har helt olika semantik.

Först teorin

DISTINCT gäller en hel tuppel. När resultatet av frågan har beräknats tar DISTINCT bort alla dubbletter från resultatet.

Antag till exempel en tabell R med följande innehåll:

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

(6 rader)

SELECT distinkt * från R kommer att resultera:

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

Observera att distinkt gäller för hela listan med projicerade attribut:alltså

select distinct * from R

är semantiskt ekvivalent med

select distinct a,b from R

Du kan inte utfärda

select a, distinct b From R

DISTINCT måste följa SELECT. Det gäller hela tupeln, inte ett attribut för resultatet.

STYRKA PÅ är ett postgresql-tillägg till språket. Det liknar, men inte identiskt, att gruppera efter.

Dess syntax är:

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

Till exempel:

 SELECT DISTINCT ON (a) * from R

Den semantik kan beskrivas på följande sätt. Beräkna frågan som vanligt--utan DISTINCT ON (a)---men innan projiceringen av resultatet, sortera det aktuella resultatet och gruppera det enligt attributlistan i DISTINCT ON (liknar gruppera efter). Gör nu projektionen med den första tuppeln i varje grupp och ignorera de andra tuplarna.

Exempel:

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

Ta sedan den första tupeln för varje olika värde på a. Vilket är samma sak som:

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

Vissa DBMS (främst sqlite) låter dig köra den här frågan:

 SELECT a,b from R group by a;

Och detta ger dig ett liknande resultat.

Postgresql tillåter denna fråga, om och endast om det finns ett funktionellt beroende från a till b. Med andra ord kommer denna fråga att vara giltig om det för någon instans av relationen R bara finns en unik tupel för varje värde eller a (så att välja den första tupeln är deterministisk:det finns bara en tupel).

Till exempel, om primärnyckeln för R är a, då a->b och:

SELECT a,b FROM R group by a

är identisk med:

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

Nu, tillbaka till ditt problem:

Första frågan:

SELECT DISTINCT count(dimension1)
FROM data_table;

beräknar antalet dimension1 (antal tuplar i datatabell där dimension1 inte är null). Denna fråga returnerar en tupel, som alltid är unik (därav DISTINCT är överflödig).

Fråga 2:

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

Detta är fråga i en fråga. Låt mig skriva om det för tydlighetens skull:

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

Låt oss beräkna första tmp_table. Som jag nämnde ovan, låt oss först ignorera DISTINCT ON och göra resten av frågan. Detta är en grupp efter dimension1. Därför kommer denna del av frågan att resultera i en tuppel per olika värde på dimension1.

Nu, DISTINCT ON. Den använder dimension1 igen. Men dimension1 är redan unik (på grund av gruppen av). Detta gör därför DISTINCT ON superflouos (det gör ingenting). Den slutliga räkningen är helt enkelt en räkning av alla tupler i gruppen.

Som du kan se finns det en likvärdighet i följande fråga (den gäller alla relationer med ett attribut a):

SELECT (DISTINCT ON a) a
FROM R

och

SELECT a FROM R group by a

och

SELECT DISTINCT a FROM R

Varning

Att använda DISTINCT ON-resultat i en fråga kan vara icke-deterministiskt för en given instans av databasen. Med andra ord kan frågan returnera olika resultat för samma tabeller.

En intressant aspekt

Distinct ON emulerar en dålig beteendet hos sqlite på ett mycket renare sätt. Antag att R har två attribut a och b:

SELECT a, b FROM R group by a

är ett olagligt uttalande i SQL. Ändå körs den på sqlite. Det tar helt enkelt ett slumpmässigt värde på b från någon av tuplarna i gruppen med samma värden för a. I Postgresql är detta uttalande olagligt. Istället måste du använda DISTINCT ON och skriva:

SELECT DISTINCT ON (a) a,b from R

Konsekvens

DISTINCT ON är användbart i en grupp när du vill komma åt ett värde som är funktionellt beroende av gruppens attribut. Med andra ord, om du vet att för varje grupp av attribut de alltid har samma värde som det tredje attributet, använd då DISTINCT ON den gruppen av attribut. Annars måste du göra en JOIN för att hämta det tredje attributet.



  1. Excel-nedladdning fast 188kb

  2. SKAPA TABELL OM INTE FINNS motsvarande i SQL Server

  3. Hur man använder ORDER BY-klausul i SQL?

  4. FEL:uppdatera eller ta bort på tabellanvändare bryter mot begränsningen för främmande nyckel fk_rails_03de2dc08c på tabellkommentarer