Exclua linhas sql nas quais os IDs não coincidem em outra tabela

160

Estou tentando excluir entradas órfãs em uma tabela mysql.

Eu tenho 2 tabelas como esta:

Quadro files:

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

tabela blob:

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

As colunas fileide idpodem ser usadas para unir as tabelas.

Quero excluir todas as linhas da tabela blobonde fileidnão podem ser encontradas na tabela files.id.

Então, usando o exemplo acima, isso excluiria as linhas: 3 e 4 (s) na blobtabela.

Martin
fonte
1
Pule para a segunda resposta se você estiver usando nulls.
Pacerier

Respostas:

326

Usando LEFT JOIN / IS NULL:

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

Usando NOT EXISTS:

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)

Aviso

Sempre que possível, execute DELETEs em uma transação (assumindo suporte - IE: não no MyISAM), para que você possa usar a reversão para reverter alterações em caso de problemas.

Pôneis OMG
fonte
12
qual é, em geral, o mais rápido dos itens acima?
Hampus Brynolf 10/04
2
Por alguma razão, a exclusão usando o LEFT JOIN não funcionou no MS SQL Server Mgmt Studio (não sei por quê; apenas reclamou do LEFT JOIN). Alguém sabe por que isso? Ele trabalhou usando NÃO EXISTE embora :)
Anna
5
FYI, aqui está uma discussão útil da eficiência relativa destes três métodos: explainextended.com/2009/09/18/...
moustachio
2
@ Pacerier - "errado" é um pouco forte. Para garantir que as pessoas entendem, as respostas fazer o trabalho, se fileidé não-nulo . Além disso, a terceira solução ( NOT IN) exige apenas que f.idnão seja nulo. Presumivelmente, essa é uma chave primária, assim seria.
precisa saber é o seguinte
2
Para as pessoas que tentam este w / SQLite: veja esta resposta
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
fonte
O que é "/ * É improvável que esta linha seja necessária, mas usando NOT IN ... * /" deveria significar?
Pacerier
1
@Pacerier - NOT IN (NULL)retorna um conjunto de resultados vazio, portanto é necessário excluir NULLs. Mas uma idcoluna provavelmente não será anulável qualquer maneira, portanto, "improvável de ser necessário"
Martin Smith
Uau boa captura. Portanto, a resposta dos omgponies está errada! not in(null)é bastante lógico, por que não funciona? Qual é a lógica por trás disso?
Pacerier
1
@bunkerdive Em seguida, use nomes de objetos de três partes que incluem o nome do banco de dados.
Martin Smith
17
DELETE FROM blob
WHERE NOT EXISTS (
    SELECT *
    FROM files
    WHERE id=blob.id
)
George
fonte
1
Eu acho que existe um files.ide blob.fileid. Suponho que sua consulta resultará em um erro.
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
fonte
3
Eu diminuí a votação porque: 1. Isso não tenta responder à pergunta no contexto que foi postado. 2. Não há explicação (e as respostas somente de código são de baixo valor no Stackoverflow). 3. NOT EXISTSjá foi publicado há 9 anos. 4. Você não promoveu a melhor prática de usar sempre letras maiúsculas para palavras-chave do MySQL. Em outras palavras, não há nada aqui que valha a pena manter - por isso também votei em excluir esta postagem.
Mckmackusa