PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jaka jest różnica między Postgres DISTINCT a DISTINCT ON?

DISTINCT i DISTINCT ON mają zupełnie inną semantykę.

Najpierw teoria

DISTINCT dotyczy całej krotki. Po obliczeniu wyniku zapytania DISTINCT usuwa z wyniku zduplikowane krotki.

Na przykład załóżmy, że tabela R ma następującą zawartość:

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

(6 rzędów)

SELECT różne * od R da wynik:

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

Zwróć uwagę, że odróżnienie dotyczy całej listy przewidywanych atrybutów:dlatego

select distinct * from R

jest semantycznie odpowiednikiem

select distinct a,b from R

Nie możesz wydać

select a, distinct b From R

DISTINCT musi następować po SELECT. Dotyczy całej krotki, a nie atrybutu wyniku.

ROZRÓŻNIONE to dodatek do języka postgresql. Jest podobny, ale nie identyczny, do grupowania według.

Jego składnia to:

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

Na przykład:

 SELECT DISTINCT ON (a) * from R

Jej semantykę można opisać następująco. Oblicz zapytanie w zwykły sposób — bez DISTINCT ON (a) — ale przed projekcją wyniku posortuj bieżący wynik i pogrupuj go zgodnie z listą atrybutów w DISTINCT ON (podobnie jak w przypadku grupowania według). Teraz wykonaj projekcję używając pierwszej krotki w każdej grupie i zignoruj ​​pozostałe krotki.

Przykład:

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

Następnie dla każdej innej wartości a weź pierwszą krotkę. Czyli to samo co:

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

Niektóre DBMS (zwłaszcza sqlite) pozwalają na uruchomienie tego zapytania:

 SELECT a,b from R group by a;

A to daje podobny wynik.

Postgresql zezwoli na to zapytanie, wtedy i tylko wtedy, gdy istnieje funkcjonalna zależność od a do b. Innymi słowy, to zapytanie będzie poprawne, jeśli dla dowolnego wystąpienia relacji R istnieje tylko jedna unikalna krotka dla każdej wartości lub a (zatem wybranie pierwszej krotki jest deterministyczne:jest tylko jedna krotka).

Na przykład, jeśli kluczem podstawowym R jest a, to a->b i:

SELECT a,b FROM R group by a

jest identyczny z:

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

A teraz wróćmy do swojego problemu:

Pierwsze zapytanie:

SELECT DISTINCT count(dimension1)
FROM data_table;

oblicza liczbę wymiar1 (liczba krotek w data_table, gdzie wymiar1 nie ma wartości null). To zapytanie zwraca jedną krotkę, która jest zawsze unikalna (stąd DISTINCTjest nadmiarowy).

Zapytanie 2:

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

To jest zapytanie w zapytaniu. Przepiszę to dla jasności:

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

Obliczmy pierwszy tmp_table. Jak wspomniałem powyżej, najpierw zignorujmy DISTINCT ON i wykonaj resztę zapytania. To jest grupowanie według wymiaru1. Dlatego ta część zapytania da w wyniku jedną krotkę na inną wartość wymiaru1.

Teraz DISTINCT ON. Używa ponownie wymiaru1. Ale wymiar1 jest już unikalny (ze względu na grupowanie według). To sprawia, że ​​DISTINCT ON superflouos (nie robi nic). Ostateczna liczba to po prostu liczba wszystkich krotek w grupie według.

Jak widać, równoważność występuje w następującym zapytaniu (dotyczy dowolnej relacji z atrybutem a):

SELECT (DISTINCT ON a) a
FROM R

i

SELECT a FROM R group by a

i

SELECT DISTINCT a FROM R

Ostrzeżenie

Użycie wyników DISTINCT ON w zapytaniu może być niedeterministyczne dla dowolnej instancji bazy danych. Innymi słowy, zapytanie może zwrócić różne wyniki dla tych samych tabel.

Jeden interesujący aspekt

Distinct ON emuluje złe zachowanie sqlite w znacznie czystszy sposób. Załóżmy, że R ma dwa atrybuty a i b:

SELECT a, b FROM R group by a

jest niedozwoloną instrukcją w SQL. Jednak działa na sqlite. Po prostu pobiera losową wartość b z dowolnej krotki w grupie o takich samych wartościach a. W Postgresql to stwierdzenie jest niedozwolone. Zamiast tego musisz użyć DISTINCT ON i napisać:

SELECT DISTINCT ON (a) a,b from R

Wniosek

DISTINCT ON jest przydatne w grupie, gdy chcesz uzyskać dostęp do wartości, która jest funkcjonalnie zależna od grupy według atrybutów. Innymi słowy, jeśli wiesz, że dla każdej grupy atrybutów mają one zawsze tę samą wartość trzeciego atrybutu, użyj opcji DISTINCT ON tej grupy atrybutów. W przeciwnym razie musiałbyś wykonać JOIN, aby pobrać ten trzeci atrybut.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wyodrębnij datę (rrrr/mm/dd) ze znacznika czasu w PostgreSQL

  2. Jak uniemożliwić PDO interpretację znaku zapytania jako symbolu zastępczego?

  3. Jak działa justify_hours() w PostgreSQL

  4. postgresql:typ danych dla skrótu wiadomości md5?

  5. Docker- django zgłasza błąd podczas łączenia się z postgres:psycopg2.OperationalError:nie można połączyć się z serwerem:Połączenie odrzucone