Pregunta

Necesito recuperar todas las filas de una tabla donde 2 columnas combinadas son todas diferentes.Entonces quiero todas las ventas que no tengan otras ventas que hayan ocurrido 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.

Entonces 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 al ir más allá de eso.

¿Fue útil?

Solución

SELECT DISTINCT a,b,c FROM t

es apenas equivalente a:

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

Es una buena idea acostumbrarse a la sintaxis GROUP BY, ya que es más poderosa.

Para tu 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
 )

Otros consejos

Si reúne las respuestas hasta el momento, las limpia y mejora, llegará a esta consulta superior:

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

Cual es mucho más rápido que cualquiera de ellos.Aumenta el rendimiento de la respuesta actualmente aceptada en un factor de 10 a 15 (en mis pruebas en PostgreSQL 8.4 y 9.1).

Pero esto todavía está lejos de ser óptimo.Usar una NOT EXISTS (anti)semiunión 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 FROM sales s1                     -- SELECT list can be empty for EXISTS
   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

db<>violín aquí
Viejo violín SQL

Clave única para identificar la fila

Si no tiene una clave principal o única para la tabla (id en el ejemplo), puede sustituir con la columna del sistema 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 principal.Agregue uno si aún no tenía uno.Sugiero un serial o un IDENTITY columna en Postgres 10+.

Relacionado:

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

La subconsulta en el EXISTS la anti-semi-unión puede dejar de evaluarse tan pronto como se encuentre el primer duplicado (no tiene sentido buscar más).Para una tabla base con pocos duplicados, esto es sólo ligeramente más eficiente.Con muchos duplicados esto se vuelve forma más eficiente.

Excluir actualizaciones vacías

Para filas que ya tienen status = 'ACTIVE' esta actualización no cambiaría nada, pero aún así insertaría una nueva versión de fila con el costo total (se aplican excepciones menores).Normalmente, no quieres esto.Agrega otro WHERE condición como se demostró arriba para evitar esto y hacerlo aún más rápido:

Si status se define NOT NULL, puedes simplificar a:

AND status <> 'ACTIVE';

Sutil diferencia en el manejo de NULL

Esta consulta (a diferencia de la respuesta actualmente aceptada por Joel) no trata los valores NULL como iguales.Las siguientes dos filas para (saleprice, saledate) calificaría como "distinto" (aunque parece idéntico al ojo humano):

(123, NULL)
(123, NULL)

También pasa en un índice único y en casi cualquier otro lugar, ya que los valores NULL no se comparan iguales según el estándar SQL.Ver:

OTOH, GROUP BY, DISTINCT o DISTINCT ON () trate los valores NULL como iguales.Utilice un estilo de consulta apropiado según lo que desee lograr.Aún puedes usar esta consulta más rápida con IS NOT DISTINCT FROM en lugar de = para que alguna o todas las comparaciones hagan que la comparación NULL sea igual.Más:

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

El problema con su consulta es que cuando usa una cláusula GROUP BY (que esencialmente hace usando distinta) solo puede usar columnas que agrupa o agrega funciones.No puede utilizar la identificación de la columna porque existen 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.

Sin embargo, esto debería funcionar (y no necesita unirse):

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.

Quiero seleccionar los valores distintos de una columna 'GrondOfLucht' pero deben ordenarse en el orden indicado en la columna 'clasificación'.No puedo obtener los distintos valores de una sola columna usando

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

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

utilice el GRUPO para seleccionar los registros de 'GrondOfLucht' en el orden indicado por 'clasificación

SELECT        GrondOfLucht
FROM            dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)

Si su DBMS no admite distintos con múltiples columnas como esta:

select distinct(col1, col2) from table

La selección múltiple en general se puede ejecutar de forma segura de la siguiente manera:

select distinct * from (select col1, col2 from table ) as x

Dado que esto puede funcionar en la mayoría de los DBMS, se espera que sea más rápido que la solución grupo por solución, ya que se evita la funcionalidad de agrupación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top