Si reúne las respuestas hasta ahora, limpia y mejora, llegaría 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. Nukes el rendimiento de la respuesta actualmente aceptada por el factor 10-15 (en mis pruebas en PostgreSQL 8.4 y 9.1).
Pero esto aún está lejos de ser óptimo. Utilice 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 de SQL
Clave única para identificar fila
Si no tiene una clave primaria o única para la tabla ( id
en el ejemplo), puede sustituirla con la columna del sistema ctid
para el propósito de esta consulta (pero no para otros fines):
AND s1.ctid <> s.ctid
Cada tabla debe tener una clave primaria. Agregue uno si aún no tiene uno. Sugiero unserial
o una IDENTITY
columna 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 engañado (no tiene sentido buscar más). Para una tabla base con pocos duplicados, esto es solo un poco más eficiente. Con muchos duplicados esto se convierte en camino más eficiente.
Excluir actualizaciones vacías
Para las filas que ya tienen status = 'ACTIVE'
esta actualización, no cambiaría nada, pero aún así se inserta una nueva versión de la fila al costo total (se aplican excepciones menores). Normalmente, no quieres esto. Agregue otra WHERE
condición como se demostró anteriormente para evitar esto y hacerlo aún más rápido:
Si status
está definido NOT NULL
, puede simplificarlo para:
AND status <> 'ACTIVE';
El tipo de datos de la columna debe ser compatible con el <>
operador. Algunos tipos json
no lo hacen. Ver:
Diferencia sutil en el manejo NULL
Esta consulta (a diferencia de la respuesta aceptada actualmente por Joel ) no trata los valores NULL como iguales. Las siguientes dos filas (saleprice, saledate)
calificarían como "distintas" (aunque parezcan idénticas al ojo humano):
(123, NULL)
(123, NULL)
También pasa un índice único y casi en cualquier otro lugar, ya que los valores NULL no se comparan igual de acuerdo con el estándar SQL. Ver:
Otoh, GROUP BY
, DISTINCT
o DISTINCT ON ()
valores treat NULL como iguales. Use un estilo de consulta apropiado según lo que quiera lograr. Todavía puede usar esta consulta más rápida con en IS NOT DISTINCT FROM
lugar de=
cualquiera o todas las comparaciones para hacer que la comparación NULL sea igual. Más:
Si se definen todas las columnas que se comparan NOT NULL
, no hay lugar para el desacuerdo.