¿Cuál es la diferencia desde un simple punto de vista de funcionalidad de eliminación duplicada?
Además del hecho de que DISTINCT
, a diferencia , GROUP BY
permite agregar datos por grupo (que ha sido mencionado por muchas otras respuestas), la diferencia más importante en mi opinión es el hecho de que las dos operaciones "suceden" en dos pasos muy diferentes en el orden lógico de operaciones que se ejecutan en una SELECT
declaración .
Estas son las operaciones más importantes:
FROM
(incluyendo JOIN
, APPLY
, etc.)
WHERE
GROUP BY
(puede eliminar duplicados)
- Agregaciones
HAVING
- Funciones de ventana
SELECT
DISTINCT
(puede eliminar duplicados)
UNION
, INTERSECT
, EXCEPT
(Se puede eliminar duplicados)
ORDER BY
OFFSET
LIMIT
Como puede ver, el orden lógico de cada operación influye en lo que se puede hacer con él y cómo influye en las operaciones posteriores. En particular, el hecho de que la GROUP BY
operación "ocurre antes" de la SELECT
operación (la proyección) significa que:
- No depende de la proyección (que puede ser una ventaja)
- No puede usar ningún valor de la proyección (lo que puede ser una desventaja)
1. No depende de la proyección.
Un ejemplo en el que no es útil depender de la proyección es si desea calcular funciones de ventana en valores distintos:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
GROUP BY rating
Cuando se ejecuta contra la base de datos Sakila , esto produce:
rating rn
-----------
G 1
NC-17 2
PG 3
PG-13 4
R 5
No se podría lograr lo mismo DISTINCT
fácilmente:
SELECT DISTINCT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
Esa consulta es "incorrecta" y produce algo como:
rating rn
------------
G 1
G 2
G 3
...
G 178
NC-17 179
NC-17 180
...
Esto no es lo que queríamos. La DISTINCT
operación "ocurre" después de la proyección, por lo que ya no podemos eliminar las DISTINCT
calificaciones porque la función de ventana ya se calculó y proyectó. Para usar DISTINCT
, tendríamos que anidar esa parte de la consulta:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM (
SELECT DISTINCT rating FROM film
) f
Nota al margen: en este caso particular, también podríamos usarDENSE_RANK()
SELECT DISTINCT rating, dense_rank() OVER (ORDER BY rating) AS rn
FROM film
2. No puede usar ningún valor de la proyección
Uno de los inconvenientes de SQL es su verbosidad a veces. Por la misma razón que hemos visto antes (es decir, el orden lógico de operaciones), no podemos agrupar "fácilmente" por algo que estamos proyectando.
Esto es SQL inválido:
SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY name
Esto es válido (repitiendo la expresión)
SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY first_name || ' ' || last_name
Esto también es válido (anidando la expresión)
SELECT name
FROM (
SELECT first_name || ' ' || last_name AS name
FROM customer
) c
GROUP BY name
He escrito sobre este tema con mayor profundidad en una publicación de blog.