sql >> Database teknologi >  >> RDS >> PostgreSQL

Hvad er forskellen mellem Postgres DISTINCT vs DISTINCT ON?

DISTINCT og DISTINCT ON har helt forskellig semantik.

Først teorien

DISTINCT gælder for en hel tupel. Når resultatet af forespørgslen er beregnet, fjerner DISTINCT alle duplikerede tuples fra resultatet.

Antag for eksempel en tabel R med følgende indhold:

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

(6 rækker)

SELECT distinkt * fra R vil resultere:

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

Bemærk, at distinkt gælder for hele listen over projekterede attributter:således

select distinct * from R
 

er semantisk ækvivalent med

select distinct a,b from R
 

Du kan ikke udstede

select a, distinct b From R
 

DISTINCT skal følge SELECT. Det gælder for hele tuple, ikke for en egenskab ved resultatet.

DISTINCER TIL er en postgresql tilføjelse til sproget. Det ligner, men ikke identisk, at gruppere efter.

Dens syntaks er:

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

For eksempel:

 SELECT DISTINCT ON (a) * from R
 

Dets semantik kan beskrives som følger. Beregn forespørgslen som sædvanligt--uden DISTINCT ON (a)---men før projektionen af ​​resultatet, sorter det aktuelle resultat og grupper det i henhold til attributlisten i DISTINCT ON (svarende til grupper efter). Lav nu projektionen med den første tuple i hver gruppe, og ignorer de andre tupler.

Eksempel:

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

Tag derefter den første tupel for hver anden værdi af a. Hvilket er det samme som:

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

Nogle DBMS (især sqlite) vil tillade dig at køre denne forespørgsel:

 SELECT a,b from R group by a;
 

Og dette giver dig et lignende resultat.

Postgresql vil tillade denne forespørgsel, hvis og kun hvis der er en funktionel afhængighed fra a til b. Med andre ord vil denne forespørgsel være gyldig, hvis der for en hvilken som helst forekomst af relationen R kun er én unik tupel for hver værdi eller a (så at vælge den første tuple er deterministisk:der er kun én tupel).

For eksempel, hvis den primære nøgle af R er a, så a->b og:

SELECT a,b FROM R group by a
 

er identisk med:

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

Nu, tilbage til dit problem:

Første forespørgsel:

SELECT DISTINCT count(dimension1)
FROM data_table;
 

beregner antallet af dimension1 (antal tuples i data_table, hvor dimension1 ikke er null). Denne forespørgsel returnerer én tupel, som altid er unik (derfor er DISTINCT overflødigt).

Forespørgsel 2:

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

Dette er forespørgsel i en forespørgsel. Lad mig omskrive det for klarhedens skyld:

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

Lad os beregne den første tmp_table. Som jeg nævnte ovenfor, lad os først ignorere DISTINCT ON og gøre resten af ​​forespørgslen. Dette er en gruppe efter dimension1. Derfor vil denne del af forespørgslen resultere i én tupel pr. forskellig værdi af dimension1.

Nu, DISTINCT ON. Den bruger dimension1 igen. Men dimension1 er allerede unik (på grund af gruppen af). Derfor gør dette DISTINCT ON superflouos (det gør ingenting). Den endelige optælling er simpelthen en optælling af alle tupler i gruppen.

Som du kan se, er der en ækvivalens i følgende forespørgsel (den gælder for enhver relation med en attribut a):

SELECT (DISTINCT ON a) a
FROM R
 

og

SELECT a FROM R group by a
 

og

SELECT DISTINCT a FROM R
 

Advarsel

Brug af DISTINCT ON-resultater i en forespørgsel kan være ikke-deterministisk for en given forekomst af databasen. Med andre ord kan forespørgslen returnere forskellige resultater for de samme tabeller.

Et interessant aspekt

Distinct ON emulerer en dårlig opførsel af sqlite på en meget renere måde. Antag, at R har to attributter a og b:

SELECT a, b FROM R group by a
 

er en ulovlig sætning i SQL. Alligevel kører den på sqlite. Det tager simpelthen en tilfældig værdi af b fra enhver af tuplerne i gruppen med samme værdier af a. I Postgresql er denne erklæring ulovlig. I stedet skal du bruge DISTINCT ON og skrive:

SELECT DISTINCT ON (a) a,b from R
 

Konsekvens

DISTINCT ON er nyttig i en gruppe, når du vil have adgang til en værdi, der er funktionelt afhængig af gruppen efter attributter. Med andre ord, hvis du ved, at for hver gruppe af attributter, de altid har den samme værdi af den tredje attribut, så brug DISTINCT ON på den gruppe af attributter. Ellers skulle du lave en JOIN for at hente den tredje egenskab.



  1. Oracle Text Indeholder og teknisk indhold

  2. Hvordan bruger du variabler i et simpelt PostgreSQL-script?

  3. Hent dynamisk parameternavne og aktuelle værdier inde i T-SQL-lagret procedure

  4. Hvordan indsætter man en række i en tabel, der kun har en enkelt autoincrement-kolonne?