Eliminar filas sql donde los ID no coinciden con otra tabla

160

Estoy tratando de eliminar entradas huérfanas en una tabla mysql.

Tengo 2 tablas como esta:

Tabla files:

| id | ....
------------
| 1  | ....
| 2  | ....
| 7  | ....
| 9  | ....

tabla blob:

| fileid | ....
------------
| 1  | ....
| 2  | ....
| 3  | ....
| 4  | ....
| 4  | ....
| 4  | ....
| 9  | ....

Las columnas fileidy idse pueden usar para unir las tablas.

Quiero eliminar todas las filas en la tabla blobdonde fileidno se pueden encontrar en la tabla files.id.

Entonces, usando el ejemplo anterior que eliminaría filas: 3 y 4 (s) en la blobtabla.

Martín
fuente
1
Pase a la segunda respuesta si está usando nulls.
Pacerier

Respuestas:

327

Usando IZQUIERDA UNIR / ES NULO:

DELETE b FROM BLOB b 
  LEFT JOIN FILES f ON f.id = b.fileid 
      WHERE f.id IS NULL

Usar NO EXISTE:

DELETE FROM BLOB 
 WHERE NOT EXISTS(SELECT NULL
                    FROM FILES f
                   WHERE f.id = fileid)

Usando NOT IN:

DELETE FROM BLOB
 WHERE fileid NOT IN (SELECT f.id 
                        FROM FILES f)

Advertencia

Siempre que sea posible, realice DELETEs dentro de una transacción (suponiendo que sea compatible - IE: no en MyISAM) para que pueda usar la reversión para revertir los cambios en caso de problemas.

Ponis OMG
fuente
12
¿Cuál es, en general, el más rápido de los anteriores?
Hampus Brynolf
2
Por alguna razón, la eliminación con el LEFT JOIN no funcionó en MS SQL Server Mgmt Studio (no estoy seguro de por qué; solo se quejó del LEFT JOIN). Alguien sabe por qué es eso? Funcionó usando NOT EXISTS :) :)
Anna
55
Para su información, aquí hay una discusión útil sobre la eficacia relativa de estos tres métodos: explainextended.com/2009/09/18/…
moustachio
2
@Pacerier: "incorrecto" es un poco fuerte. Para asegurarse de que la gente a entender, las respuestas hacen el trabajo si fileides no anulable . Además, la tercera solución ( NOT IN) solo requiere que f.idno sea anulable. Presumiblemente, esa es una clave principal, por lo que sería.
ToolmakerSteve
2
Para las personas que intentan esto con SQLite: vea esta respuesta
bunkerdive
26
DELETE FROM blob 
WHERE fileid NOT IN 
       (SELECT id 
        FROM files 
        WHERE id is NOT NULL/*This line is unlikely to be needed 
                               but using NOT IN...*/
      )
Martin Smith
fuente
¿Qué es "/ * es poco probable que se necesite esta línea, pero se supone que usar NOT IN ... * /" significa?
Pacerier
1
@Pacerier: NOT IN (NULL)devuelve un conjunto de resultados vacío, por lo que los NULL deben excluirse. Pero una idcolumna probablemente no será anulable de todos modos, por lo tanto, "es poco probable que sea necesaria"
Martin Smith
Wow buena captura. ¡Entonces la respuesta de omgponies es incorrecta! not in(null)es bastante lógico, ¿por qué no funciona? ¿Cuál es la razón detrás de eso?
Pacerier
1
@bunkerdive Luego use nombres de objetos de tres partes que incluyan el nombre de la base de datos.
Martin Smith
17
DELETE FROM blob
WHERE NOT EXISTS (
    SELECT *
    FROM files
    WHERE id=blob.id
)
Jorge
fuente
1
Creo que hay un files.idy blob.fileid. Supongo que su consulta dará como resultado un error.
jww
-8
delete from table1 t1 
    WHERE not exists (select id from table2 where related_field_in_t2=t1.id) 
    AND not exists (select id from table3 where related_field_in_t3=t1.id) 
    AND not exists (select id from table4 where related_field_t4=t1.id) 
    AND not exists (select id from table5 where related_field_t5=t1.id);
Kamrujjaman Khan
fuente
3
He votado a favor porque: 1. Esto no intenta responder la pregunta en el contexto que se publicó. 2. No hay explicación (y las respuestas de solo código son de bajo valor en Stackoverflow). 3. NOT EXISTSya fue publicado hace 9 años. 4. No ha promovido la mejor práctica de usar consistentemente mayúsculas para palabras clave MySQL. En otras palabras, no hay nada aquí que valga la pena mantener, es por eso que también he votado para eliminar esta publicación.
mickmackusa