¿Cómo eliminar de select en MySQL?

86

Este código no funciona para MySQL 5.0, cómo reescribirlo para que funcione

DELETE FROM posts where id=(SELECT id FROM posts GROUP BY id  HAVING ( COUNT(id) > 1 ))

Quiero eliminar columnas que no tienen una identificación única. Agregaré que la mayoría de las veces es solo una identificación (probé la sintaxis in y no funciona tan bien).

IAdapter
fuente

Respuestas:

212

SELECTLas (sub) consultas devuelven conjuntos de resultados . Por lo que necesita usar IN, no =en su WHEREcláusula.

Además, como se muestra en esta respuesta, no puede modificar la misma tabla desde una subconsulta dentro de la misma consulta. Sin embargo, puede SELECTentonces DELETEen consultas separadas, o anidar otra subconsulta y alias el resultado de la subconsulta interna (aunque parece bastante hacky):

DELETE FROM posts WHERE id IN (
    SELECT * FROM (
        SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
    ) AS p
)

O use combinaciones como sugiere Mchl .

BoltClock
fuente
1
Tenía una mesa con 150 llaves duplicadas. Ejecuté la consulta anterior y decía "144 filas afectadas", pero todavía había claves duplicadas. Entonces ejecuté la consulta nuevamente y dice 5 filas afectadas, nuevamente: 1 fila afectada. Luego, todas las llaves duplicadas se fueron. ¿Por qué es esto?
Alex
Esto está sucediendo porque solo está eliminando 1 entrada de cada conjunto de duplicados:SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
havvg
# 1248 - Cada tabla derivada debe tener su propio alias
thang
@thang: Por eso dije alias de la subconsulta interna.
BoltClock
1
¿Podría explicar qué significa "As p"?
Jugador de críquet
22
DELETE 
  p1
  FROM posts AS p1 
CROSS JOIN (
  SELECT ID FROM posts GROUP BY id HAVING COUNT(id) > 1
) AS p2
USING (id)
Mchl
fuente
Esto parece funcionar, pero estoy confundido por la sintaxis y no puedo encontrar ningún recurso en otro lugar para explicarlo. CROSS JOINaparentemente realiza una unión cartesiana, por lo que parece que esto podría hacer un trabajo innecesario o funcionar de manera subóptima. ¿Alguien podría explicarlo?
wintron
Hará un producto cartesiano solo si no hay una USINGcláusula. Con USINGel producto se limita a pares que tengan el mismo valor en la idcolumna, por lo que de hecho es muy limitado.
Mchl
¿Podrías hacer lo mismo con la unión interna? IEDELETE p1 FROM posts AS p1 INNER JOIN ( SELECT ID FROM posts GROUP BY id HAVING COUNT(id) > 1 ) AS p2 ON p2.ID=p1.ID
Kodos Johnson
1
@ Andrew: Sí. Funcionalmente, estas uniones son exactamente iguales.
Mchl
5

puedes usar la unión interna:

DELETE 
    ps 
FROM 
    posts ps INNER JOIN 
         (SELECT 
           distinct id 
         FROM 
             posts 
         GROUP BY id  
      HAVING COUNT(id) > 1 ) dubids on dubids.id = ps.id  
Charif DZ
fuente
0

Si desea eliminar todos los duplicados, pero uno de cada conjunto de duplicados, esta es una solución:

DELETE posts
FROM posts
LEFT JOIN (
    SELECT id
    FROM posts
    GROUP BY id
    HAVING COUNT(id) = 1

    UNION

    SELECT id
    FROM posts
    GROUP BY id
    HAVING COUNT(id) != 1
) AS duplicate USING (id)
WHERE duplicate.id IS NULL;
havvg
fuente