PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Каква е разликата между Postgres DISTINCT срещу DISTINCT ON?

DISTINCT и DISTINCT ON имат напълно различна семантика.

Първо теорията

DISTINCT се прилага към цял кортеж. След като резултатът от заявката бъде изчислен, DISTINCT премахва всички дублиращи се кортежи от резултата.

Да приемем например таблица R със следното съдържание:

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

(6 реда)

SELECT distinct * from R ще доведе до:

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

Имайте предвид, че distinct се отнася за целия списък с проектирани атрибути:така

select distinct * from R

е семантично еквивалентен на

select distinct a,b from R

Не можете да издавате

select a, distinct b From R

DISTINCT трябва да следва SELECT. Прилага се към целия кортеж, а не към атрибут на резултата.

ОТЛИЧЕН НА е postgresql допълнение към езика. Подобно е, но не е идентично на групирането по.

Синтаксисът му е:

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

Например:

 SELECT DISTINCT ON (a) * from R

Семантиката му може да бъде описана по следния начин. Изчислете заявката както обикновено--без DISTINCT ON (a)---но преди проекцията на резултата сортирайте текущия резултат и го групирайте според списъка с атрибути в DISTINCT ON (подобно на групиране по). Сега направете проекцията, като използвате първия кортеж във всяка група и игнорирайте другите кортежи.

Пример:

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

След това за всяка различна стойност на a вземете първия кортеж. Което е същото като:

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

Някои СУБД (най-вече sqlite) ще ви позволят да изпълните тази заявка:

 SELECT a,b from R group by a;

И това ви дава подобен резултат.

Postgresql ще позволи тази заявка, ако и само ако има функционална зависимост от a към b. С други думи, тази заявка ще бъде валидна, ако за всеки екземпляр на релацията R има само един уникален кортеж за всяка стойност или a (по този начин изборът на първия кортеж е детерминистичен:има само един кортеж).

Например, ако първичният ключ на R е a, тогава a->b и:

SELECT a,b FROM R group by a

е идентичен на:

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

А сега да се върнем към вашия проблем:

Първо запитване:

SELECT DISTINCT count(dimension1)
FROM data_table;

изчислява броя на dimension1 (брой кортежи в data_table, където dimension1 не е null). Тази заявка връща един кортеж, който винаги е уникален (следователно DISTINCT е излишен).

Заявка 2:

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

Това е заявка в заявка. Нека го пренапиша за яснота:

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

Нека изчислим първата tmp_table. Както споменах по-горе, нека първо игнорираме DISTINCT ON и да направим останалата част от заявката. Това е група по размер1. Следователно тази част от заявката ще доведе до един кортеж за различна стойност на dimension1.

Сега, DISTINCT ON. Той отново използва измерение1. Но dimension1 вече е уникален (поради групирането по). Следователно това прави DISTINCT ON superflouos (не прави нищо). Окончателният брой е просто брой на всички кортежи в групата по.

Както можете да видите, има еквивалентност в следната заявка (тя се отнася за всяка релация с атрибут a):

SELECT (DISTINCT ON a) a
FROM R

и

SELECT a FROM R group by a

и

SELECT DISTINCT a FROM R

Предупреждение

Използването на DISTINCT ON резултати в заявка може да не е детерминистично за всяко дадено копие на базата данни. С други думи, заявката може да върне различни резултати за едни и същи таблици.

Един интересен аспект

Distinct ON емулира лошо поведение на sqlite по много по-чист начин. Да приемем, че R има два атрибута a и b:

SELECT a, b FROM R group by a

е незаконен израз в SQL. Въпреки това работи на sqlite. Той просто взема произволна стойност на b от който и да е от кортежите в групата от еднакви стойности на a. В Postgresql това твърдение е незаконно. Вместо това трябва да използвате DISTINCT ON и да напишете:

SELECT DISTINCT ON (a) a,b from R

Следствие

DISTINCT ON е полезен в група, когато искате да получите достъп до стойност, която е функционално зависима от групата по атрибути. С други думи, ако знаете, че за всяка група атрибути те винаги имат една и съща стойност на третия атрибут, тогава използвайте DISTINCT ON тази група атрибути. В противен случай ще трябва да направите JOIN, за да извлечете този трети атрибут.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Postgresql:ФАТАЛНО:ролята не съществува

  2. Автоматично увеличаване на колоната на таблицата

  3. Буфери (кръг) в PostGIS

  4. Проверете статистическите цели в PostgreSQL

  5. Симулирате CREATE DATABASE, АКО НЕ СЪЩЕСТВУВА за PostgreSQL?