¿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).

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 .


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)

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  

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;
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.