PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Was ist der Unterschied zwischen Postgres DISTINCT und DISTINCT ON?

DISTINCT und DISTINCT ON haben eine völlig unterschiedliche Semantik.

Zuerst die Theorie

DISTINCT gilt für ein ganzes Tupel. Sobald das Ergebnis der Abfrage berechnet ist, entfernt DISTINCT alle doppelten Tupel aus dem Ergebnis.

Nehmen Sie beispielsweise eine Tabelle R mit folgendem Inhalt an:

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

(6 Reihen)

SELECT different * from R ergibt:

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

Beachten Sie, dass distinct für die gesamte Liste der projizierten Attribute gilt:also

select distinct * from R

ist semantisch äquivalent zu

select distinct a,b from R

Sie können nicht ausstellen

select a, distinct b From R

DISTINCT muss auf SELECT folgen. Es gilt für das gesamte Tupel, nicht für ein Attribut des Ergebnisses.

DISTINCT ON ist eine postgresql-Ergänzung zur Sprache. Es ist ähnlich, aber nicht identisch mit Gruppieren nach.

Seine Syntax ist:

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

Zum Beispiel:

 SELECT DISTINCT ON (a) * from R

Die Semantik kann wie folgt beschrieben werden. Berechnen Sie die Abfrage wie gewohnt – ohne das DISTINCT ON (a) – aber sortieren Sie vor der Hochrechnung des Ergebnisses das aktuelle Ergebnis und gruppieren Sie es gemäß der Attributliste in DISTINCT ON (ähnlich wie group by). Führen Sie nun die Projektion mit dem ersten Tupel in jeder Gruppe durch und ignorieren Sie die anderen Tupel.

Beispiel:

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

Nimm dann für jeden anderen Wert von a das erste Tupel. Was dasselbe ist wie:

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

Einige DBMS (insbesondere sqlite) erlauben Ihnen, diese Abfrage auszuführen:

 SELECT a,b from R group by a;

Und dies führt zu einem ähnlichen Ergebnis.

Postgresql erlaubt diese Abfrage nur dann, wenn eine funktionale Abhängigkeit von a nach b besteht. Mit anderen Worten, diese Abfrage ist gültig, wenn es für jede Instanz der Relation R nur ein eindeutiges Tupel für jeden Wert oder a gibt (daher ist die Auswahl des ersten Tupels deterministisch:es gibt nur ein Tupel).

Wenn zum Beispiel der Primärschlüssel von R a ist, dann a->b und:

SELECT a,b FROM R group by a

ist identisch mit:

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

Nun zurück zu Ihrem Problem:

Erste Abfrage:

SELECT DISTINCT count(dimension1)
FROM data_table;

berechnet die Anzahl von dimension1 (Anzahl der Tupel in data_table, bei denen dimension1 nicht null ist). Diese Abfrage gibt ein Tupel zurück, das immer eindeutig ist (daher ist DISTINCT redundant).

Abfrage 2:

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

Dies ist eine Abfrage in einer Abfrage. Lassen Sie es mich zur Verdeutlichung umschreiben:

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

Lassen Sie uns zuerst tmp_table berechnen. Wie oben erwähnt, lassen Sie uns zunächst DISTINCT ON ignorieren und den Rest der Abfrage durchführen. Dies ist eine Gruppierung nach Dimension1. Daher ergibt dieser Teil der Abfrage ein Tupel pro unterschiedlichem Wert von dimension1.

Nun, das DISTINCT ON. Es verwendet wieder Dimension1. Aber dimension1 ist bereits eindeutig (aufgrund der Gruppierung nach). Daher macht dies DISTINCT ON überflüssig (es macht nichts). Die endgültige Zählung ist einfach eine Zählung aller Tupel in der Gruppe von.

Wie Sie sehen können, gibt es eine Äquivalenz in der folgenden Abfrage (sie gilt für jede Beziehung mit einem Attribut a):

SELECT (DISTINCT ON a) a
FROM R

und

SELECT a FROM R group by a

und

SELECT DISTINCT a FROM R

Warnung

Die Verwendung von DISTINCT ON-Ergebnissen in einer Abfrage kann für die jeweilige Instanz der Datenbank nicht deterministisch sein. Mit anderen Worten, die Abfrage kann für dieselben Tabellen unterschiedliche Ergebnisse zurückgeben.

Ein interessanter Aspekt

Distinct ON emuliert ein schlechtes Verhalten von sqlite in einer viel saubereren Art und Weise. Angenommen, R hat zwei Attribute a und b:

SELECT a, b FROM R group by a

ist eine illegale Anweisung in SQL. Es läuft jedoch auf SQLite. Es nimmt einfach einen zufälligen Wert von b aus einem der Tupel in der Gruppe gleicher Werte von a. In Postgresql ist diese Anweisung illegal. Stattdessen müssen Sie DISTINCT ON verwenden und schreiben:

SELECT DISTINCT ON (a) a,b from R

Folge

DISTINCT ON ist in einer Gruppierung nach nützlich, wenn Sie auf einen Wert zugreifen möchten, der funktional von den Gruppierungsattributen abhängig ist. Mit anderen Worten, wenn Sie wissen, dass jede Gruppe von Attributen immer denselben Wert des dritten Attributs hat, dann verwenden Sie DISTINCT ON für diese Gruppe von Attributen. Andernfalls müssten Sie einen JOIN erstellen, um dieses dritte Attribut abzurufen.