¿Cómo puedo (o puedo) SELECCIONAR DISTINTO en varias columnas?


Necesito recuperar todas las filas de una tabla donde 2 columnas combinadas son todas diferentes. Así que quiero todas las ventas que no tienen ninguna otra venta que ocurrió en el mismo día por el mismo precio. Las ventas que son únicas según el día y el precio se actualizarán a un estado activo.

Así que estoy pensando:

UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
             FROM sales
             HAVING count = 1)

Pero me duele el cerebro yendo más lejos que eso.

Author: Erwin Brandstetter, 2008-09-10

4 answers

SELECT DISTINCT a,b,c FROM t

Es aproximadamente equivalente a:

SELECT a,b,c FROM t GROUP BY a,b,c

Es una buena idea acostumbrarse al GRUPO por sintaxis, ya que es más poderoso.

Para su consulta, lo haría así:

UPDATE sales
SET status='ACTIVE'
WHERE id IN
(
    SELECT id
    FROM sales S
    INNER JOIN
    (
        SELECT saleprice, saledate
        FROM sales
        GROUP BY saleprice, saledate
        HAVING COUNT(*) = 1 
    ) T
    ON S.saleprice=T.saleprice AND s.saledate=T.saledate
 )
 379
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-10 15:55:08

Si juntas las respuestas hasta ahora, limpias y mejoras, llegarías a esta pregunta superior:{[24]]}

UPDATE sales
SET    status = 'ACTIVE'
WHERE  (saleprice, saledate) IN (
    SELECT saleprice, saledate
    FROM   sales
    GROUP  BY saleprice, saledate
    HAVING count(*) = 1 
    );

Que es mucho más rápido que cualquiera de ellos. Nukes el rendimiento de la respuesta actualmente aceptada por factor 10 - 15 (en mis pruebas en PostgreSQL 8.4 y 9.1).

Pero esto todavía está lejos de ser óptimo. Use un NOT EXISTS (anti -) semi-join para un rendimiento aún mejor. EXISTS es SQL estándar, ha existido desde siempre (al menos desde PostgreSQL 7.2, mucho antes de que se hiciera esta pregunta) y se ajusta perfectamente a los requisitos presentados:

UPDATE sales s
SET    status = 'ACTIVE'
WHERE  NOT EXISTS (
   SELECT 1
   FROM   sales s1
   WHERE  s.saleprice = s1.saleprice
   AND    s.saledate  = s1.saledate
   AND    s.id <> s1.id                     -- except for row itself
   );
AND    s.status IS DISTINCT FROM 'ACTIVE';  -- avoid empty updates. see below

Violín SQL.

Clave única para identificar la fila

Si no tiene una clave primaria o única para la tabla (id en el ejemplo), puede sustituirla por la columna system ctid para el propósito de esta consulta (pero no para otros propósitos):

   AND    s1.ctid <> s.ctid

Cada tabla debe tener una clave primaria. Agrega uno si aún no tienes uno. Sugiero una columna serial o IDENTITY en Postgres 10+.

Relacionado:

¿Cómo es esto más rápido?

La subconsulta en el EXISTS (anti-)semi-join puede dejar de evaluar tan pronto como se encuentre el primer dupe (no tiene sentido buscar más). Para una tabla base con pocos duplicados, esto solo es ligeramente más eficiente. Con muchos duplicados esto se convierte en camino más eficiente.

Excluir actualizaciones vacías

Si algunas o muchas filas ya tienen status = 'ACTIVE', su actualización no cambiaría nada, pero aún así insertaría una nueva versión de fila al costo completo (se aplican excepciones menores). Normalmente, no quieres esto. Agregue otra condición WHERE como se demostró anteriormente para hacer esto aún más rápido:

Si status está definido NOT NULL, puede simplificar a:

AND status <> 'ACTIVE';

Diferencia sutil en el manejo NULO

Esta consulta (a diferencia de la respuesta actualmente aceptada por Joel ) no trata los valores NULOS como iguales. Estas dos filas para (saleprice, saledate) calificarían como "distintas" (aunque parecen idénticas al ojo humano):

(123, NULL)
(123, NULL)

También pasa en un índice único y casi en cualquier otro lugar, ya que los valores NULOS no se comparan igual de acuerdo con el estándar SQL. Véase:

OTOH, GROUP BY o DISTINCT o DISTINCT ON () tratan los valores NULOS como iguales. Utilizar un estilo de consulta apropiado dependiendo de lo que desea lograr. Aún puede usar este estilo de consulta más rápido usando IS NOT DISTINCT FROM en lugar de = para que cualquiera o todas las comparaciones hagan que NULL compare sea igual. Más:

Si todas las columnas que se comparan están definidas NOT NULL, no hay lugar para el desacuerdo.

 295
Author: Erwin Brandstetter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-13 12:24:49

El problema con su consulta es que cuando se usa una cláusula GROUP BY (que esencialmente se hace usando distinct) solo se pueden usar columnas que se agrupan por o funciones agregadas. No puede usar el id de columna porque hay valores potencialmente diferentes. En su caso, siempre hay un solo valor debido a la cláusula HAVING, pero la mayoría de los RDBMS no son lo suficientemente inteligentes como para reconocerlo.

Esto debería funcionar sin embargo (y no necesita una unión):

UPDATE sales
SET status='ACTIVE'
WHERE id IN (
  SELECT MIN(id) FROM sales
  GROUP BY saleprice, saledate
  HAVING COUNT(id) = 1
)

También puedes usar MAX o AVG en lugar de MIN, solo es importante usar una función que devuelva el valor de la columna si solo hay una fila coincidente.

 22
Author: Christian Berg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-10 16:17:13

Quiero seleccionar los distintos valores de una columna 'GrondOfLucht', pero deben ordenarse en el orden que se indica en la columna 'sorting'. No puedo obtener los distintos valores de una sola columna usando

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

También dará a la columna 'sorting' y porque 'GrondOfLucht' Y 'sorting' no son únicos, el resultado será TODAS las filas.

Utilice el GRUPO para seleccionar los registros de ' GrondOfLucht 'en el orden dado por' sorting

SELECT        GrondOfLucht
FROM            dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)
 1
Author: frans eilering,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-13 10:41:47