sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Cuál es la diferencia entre Postgres DISTINCT y DISTINCT ON?

DISTINCT y DISTINCT ON tienen una semántica completamente diferente.

Primero la teoría

DISTINCT se aplica a una tupla completa. Una vez que se calcula el resultado de la consulta, DISTINCT elimina cualquier tupla duplicada del resultado.

Por ejemplo, suponga una tabla R con los siguientes contenidos:

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

(6 filas)

SELECCIONE distinto * de R dará como resultado:

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

Tenga en cuenta que distinto se aplica a toda la lista de atributos proyectados:por lo tanto

select distinct * from R

es semánticamente equivalente a

select distinct a,b from R

No puede emitir

select a, distinct b From R

DISTINCT debe seguir a SELECT. Se aplica a toda la tupla, no a un atributo del resultado.

DISTINTO EN es una adición postgresql al lenguaje. Es similar, pero no idéntico, a agrupar por.

Su sintaxis es:

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

Por ejemplo:

 SELECT DISTINCT ON (a) * from R

Su semántica se puede describir de la siguiente manera. Calcule la consulta como de costumbre, sin DISTINCT ON (a), pero antes de la proyección del resultado, ordene el resultado actual y agrúpelo según la lista de atributos en DISTINCT ON (similar a agrupar por). Ahora, haz la proyección usando la primera tupla de cada grupo e ignora las otras tuplas.

Ejemplo:

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

Luego, para cada valor diferente de a, tome la primera tupla. Que es lo mismo que:

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

Algunos DBMS (sobre todo sqlite) le permitirán ejecutar esta consulta:

 SELECT a,b from R group by a;

Y esto te da un resultado similar.

Postgresql permitirá esta consulta, si y solo si existe una dependencia funcional de a a b. En otras palabras, esta consulta será válida si para cualquier instancia de la relación R, solo hay una tupla única para cada valor o a (por lo tanto, seleccionar la primera tupla es determinista:solo hay una tupla).

Por ejemplo, si la clave primaria de R es a, entonces a->b y:

SELECT a,b FROM R group by a

es idéntico a:

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

Ahora, volviendo a tu problema:

Primera consulta:

SELECT DISTINCT count(dimension1)
FROM data_table;

calcula el recuento de dimension1 (número de tuplas en data_table donde dimension1 no es nulo). Esta consulta devuelve una tupla, que siempre es única (por lo tanto, DISTINCT es redundante).

Consulta 2:

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

Esta es una consulta en una consulta. Déjame reescribirlo para mayor claridad:

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

Calculemos primero tmp_table. Como mencioné anteriormente, primero ignoremos DISTINCT ON y hagamos el resto de la consulta. Este es un grupo por dimensión1. Por lo tanto, esta parte de la consulta dará como resultado una tupla por valor diferente de dimensión1.

Ahora, el DISTINTO ENCENDIDO. Utiliza dimension1 de nuevo. Pero dimension1 ya es único (debido al grupo por). Por lo tanto, esto hace que DISTINCT ON sea superfluo (no hace nada). El recuento final es simplemente un recuento de todas las tuplas del grupo.

Como puede ver, hay una equivalencia en la siguiente consulta (se aplica a cualquier relación con un atributo a):

SELECT (DISTINCT ON a) a
FROM R

y

SELECT a FROM R group by a

y

SELECT DISTINCT a FROM R

Advertencia

El uso de resultados DISTINCT ON en una consulta puede no ser determinista para cualquier instancia dada de la base de datos. En otras palabras, la consulta puede devolver resultados diferentes para las mismas tablas.

Un aspecto interesante

Distinct ON emula un malo comportamiento de sqlite de una manera mucho más limpia. Suponga que R tiene dos atributos a y b:

SELECT a, b FROM R group by a

es una declaración ilegal en SQL. Sin embargo, se ejecuta en sqlite. Simplemente toma un valor aleatorio de b de cualquiera de las tuplas en el grupo de los mismos valores de a. En Postgresql, esta declaración es ilegal. En su lugar, debe usar DISTINCT ON y escribir:

SELECT DISTINCT ON (a) a,b from R

Corolario

DISTINCT ON es útil en un grupo por cuando desea acceder a un valor que depende funcionalmente del grupo por atributos. En otras palabras, si sabe que para cada grupo de atributos siempre tienen el mismo valor del tercer atributo, entonces use DISTINCT ON ese grupo de atributos. De lo contrario, tendría que hacer un JOIN para recuperar ese tercer atributo.