Excluir com Join no MySQL

501

Aqui está o script para criar minhas tabelas:

CREATE TABLE clients (
   client_i INT(11),
   PRIMARY KEY (client_id)
);
CREATE TABLE projects (
   project_id INT(11) UNSIGNED,
   client_id INT(11) UNSIGNED,
   PRIMARY KEY (project_id)
);
CREATE TABLE posts (
   post_id INT(11) UNSIGNED,
   project_id INT(11) UNSIGNED,
   PRIMARY KEY (post_id)
);

No meu código PHP, ao excluir um cliente, desejo excluir todas as postagens de projetos:

DELETE 
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id;

A tabela mensagens não tem uma chave estrangeira client_id, única project_id. Quero excluir as postagens em projetos que passaram client_id.

No momento, isso não está funcionando porque nenhuma postagem foi excluída.

GeekJock
fonte
10
Acho Yehosef resposta deve ser o único aceito, desde que ele usa Junte como você pediu e que ele executa melhor do que usar uma cláusula IN como yukondude proposta ...
Gerardo Grignoli
2
O padrão preferido é um DELETE posts FROM posts JOIN projects ..., e não um IN (subquery)padrão. (A resposta de Yehosef dá um exemplo do padrão preferido.)
spencer7593
@ GerardoGrignoli, ele tem um desempenho melhor para um determinado mecanismo ou versão do MySQL? Não há razão para que as duas consultas tenham um desempenho diferente, pois são idênticas ao AFAIK. Claro, se eu tive um níquel para todas as vezes o meu otimizador de consulta fez algo estúpido ....
Paul Draper
Você também pode usar aliaso nome da tabela e usá-lo.
Biniam

Respostas:

1254

Você só precisa especificar que deseja excluir as entradas da poststabela:

DELETE posts
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

EDIT: Para mais informações, você pode ver esta resposta alternativa

Yehosef
fonte
117
Deve-se observar que esta é a resposta correta porque a junção obriga a usar "EXCLUIR postagens de postagens" em vez das normais "EXCLUIR postagens DE", pois a tabela a ser excluída não é mais inequívoca. Obrigado!
Siannopollo
8
Note que você não pode usar o 'como' método aqui por exemplo junção interna projectos como p sobre p.project_id ...
ZZAPPER
14
Na verdade, você pode usar um alias para tabelas unidas, mas não para a tabela principal (postagens). "EXCLUIR postagens de postagens INNER JOIN projetos p ON p.project_id = posts.project_id"
Weboide 29/12/12
85
"Se você declarar um alias para uma tabela, deverá usá-lo ao se referir à tabela" assim:DELETE d FROM posts AS d JOIN projects AS p ON ...
KCD
14
esta é a melhor resposta, pois você pode até mesmo excluir de ambas as tabelas em uma açãoDELETE posts , projects FROM posts INNER JOIN projects ON projects.project_id = posts.project_id WHERE projects.client_id = :client_id
Developerium
84

Como você seleciona várias tabelas, a tabela da qual excluir não é mais inequívoca. Você precisa selecionar :

DELETE posts FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

Nesse caso, table_name1e table_name2são a mesma tabela, então isso funcionará:

DELETE projects FROM posts INNER JOIN [...]

Você pode até excluir das duas tabelas se desejar:

DELETE posts, projects FROM posts INNER JOIN [...]

Observe que order bye limit não funciona para exclusões de várias tabelas .

Lembre-se também de que, se você declarar um alias para uma tabela, deverá usá-lo ao se referir à tabela:

DELETE p FROM posts as p INNER JOIN [...]

Contribuições de Carpetsmoker e etc .

Pacerier
fonte
3
Se você está dando uma resposta melhor - pelo menos você pode tornar o SQL mais legível. Todas as outras referências SQL nesta pergunta possuem palavras-chave em maiúsculas (exceto uma com 0 votos). Não sei por que você reverteu minhas edições.
Yehosef 13/04
3
@Yehosef, Há um grupo de pessoas que acha o CAPS realmente gritante. Acredito que não sou o único, já vi muitas pessoas usando o estilo minúsculo.
Pacerier
1
bastante justo - Eu respeito o seu direito de escrever a sua resposta no estilo que você gosta;)
Yehosef
7
Para adicionar à discussão sobre maiúsculas / sem maiúsculas, é verdade, você pode usar o estilo que quiser, mas na sua resposta, na verdade, você está misturando estilos onde achar conveniente - o ONcapitalizado. Para desenvolvedores menos experientes, isso pode indicar que não há problema em ser confuso e inconsistente em termos de estilo.
Shade
16
CAPS KEYWORDS não são gritantes. eles estão fazendo as consultas lidas;)
Sachem
50

Ou a mesma coisa, com uma sintaxe ligeiramente diferente (mais amigável da IMO):

DELETE FROM posts 
USING posts, projects 
WHERE projects.project_id = posts.project_id AND projects.client_id = :client_id;

BTW, com o mysql usando junções é quase sempre muito mais rápido que as subconsultas ...

ivanhoe
fonte
O que significa o USING?
CMCDragonkai
1
Boa explicação de USING: stackoverflow.com/questions/11366006/mysql-on-vs-using
bigtex777
10
@ bigtex777: Observe que a palavra-chave USING nas instruções SELECT tem pouco a ver com a mesma palavra-chave em uma instrução DELETE. Em seleciona especifica a lista de colunas para juntar-se em, enquanto em DELETEs é uma lista de todas as tabelas em uma junção
Ivanhoe
42

Você também pode usar o ALIAS assim funciona, apenas usei no meu banco de dados! É necessário excluir a tabela!

DELETE t FROM posts t
INNER JOIN projects p ON t.project_id = p.project_id
AND t.client_id = p.client_id
Propriedade Espanha
fonte
1
isto é útil em chave composta junta-se a evitar a repetição dos nomes de tabela
Marquez
1
"Na verdade, você pode usar um alias para tabelas unidas, mas não para a tabela principal (postagens). 'EXCLUIR postagens DE postagens INNER JOIN projetos p ON p.project_id = posts.project_id'" - @ Weboide
Jeaf Gilbert
2
Na verdade (citando dev.mysql.com/doc/refman/5.0/en/delete.html ) "Se você declarar um alias para uma tabela, deverá usá-lo ao se referir à tabela: DELETE t1 FROM test AS t1, test2 WHERE ... ", portanto, usar um alias é bom.
Peter Bowers
25

Estou mais acostumado com a solução de subconsulta para isso, mas ainda não tentei no MySQL:

DELETE  FROM posts
WHERE   project_id IN (
            SELECT  project_id
            FROM    projects
            WHERE   client_id = :client_id
        );
yukondude
fonte
85
Você realmente deve evitar usar a palavra-chave IN no SQL (mesmo que seja mais fácil de entender para iniciantes) e usar JOIN (quando possível), pois as subconsultas geralmente tornam as coisas muito mais lentas.
user276648
14
Isso tende a travar o banco de dados quando há um grande número de linhas retornadas pela subconsulta. Também é imensamente lento.
23412 Raj
2
@yukondude De fato, "IN" é muito mais fácil de entender do que "JOIN" no dia 1º, e é por isso que as pessoas que não estão realmente familiarizadas com o SQL acabam escrevendo "IN" em todos os lugares, enquanto poderiam usar "JOIN", que tem um desempenho melhor ( ou muito melhor, dependendo da consulta). Lembro-me de vários anos atrás, quase todas as minhas consultas SQL seriam reescritas por alguém que realmente soubesse escrever boas consultas. Por isso, adicionei o comentário para evitar "IN", para que as pessoas saibam que, se possível, devem evitar usá-lo.
User276648
10
O motivo pelo qual cheguei a esta página é porque a consulta que escrevi com uma instrução IN era lenta. Definitivamente, evite a resposta aceita aqui.
MikeKulls
4
Por mais antiga que seja essa pergunta, é importante saber por que você deve usar JOIN em vez de IN. Quando aquela condição em que é executada em uma linha, ela executa essa consulta dentro de IN. Isso significa que, se houver 100 linhas que precisam ser verificadas nesse WHERE, essa subconsulta será executada 100 vezes. Enquanto um JOIN será executado apenas UMA VEZ. Assim, à medida que seu banco de dados aumenta, essa consulta vai demorar mais e mais para ser concluída. @markus só porque algo não é crítico, não significa que você deve escrever um código incorreto. Escrever um pouco melhor poupará muito tempo e dor de cabeça no futuro. :)
RisingSun
11

MySQL DELETE registra com JOIN

Você geralmente usa INNER JOIN na instrução SELECT para selecionar registros de uma tabela que possui registros correspondentes em outras tabelas. Também podemos usar a cláusula INNER JOIN com a instrução DELETE para excluir registros de uma tabela e também os registros correspondentes em outras tabelas, por exemplo, para excluir registros das tabelas T1 e T2 que atendem a uma condição específica, use a seguinte instrução:

DELETE T1, T2
FROM T1
INNER JOIN T2 ON T1.key = T2.key
WHERE condition

Observe que você coloca os nomes das tabelas T1 e T2 entre DELETE e FROM. Se você omitir a tabela T1, a instrução DELETE excluirá apenas os registros da tabela T2 e, se você omitir a tabela T2, somente os registros da tabela T1 serão excluídos.

A condição de junção T1.key = T2.key especifica os registros correspondentes na tabela T2 que precisam ser excluídos.

A condição na cláusula WHERE especifica quais registros no T1 e T2 que precisam ser excluídos.

Aman Garg
fonte
11

Exclusão de tabela única:

Para excluir entradas da poststabela:

DELETE ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Para excluir entradas da projectstabela:

DELETE pj 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Para excluir entradas da clientstabela:

DELETE C
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Excluir várias tabelas:

Para excluir entradas de várias tabelas dos resultados associados, é necessário especificar os nomes das tabelas depois DELETEcomo lista separada por vírgula:

Suponha que você queira excluir entradas de todas as três tabelas ( posts, projects, clients) para um determinado cliente:

DELETE C,pj,ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id
1000111
fonte
7

Tente como abaixo:

DELETE posts.*,projects.* 
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id;
Sangeetha Narayana Moorthy
fonte
4

Outro método de exclusão usando uma sub-seleção que é melhor do que usar INseriaWHERE EXISTS

DELETE  FROM posts
WHERE   EXISTS ( SELECT  1 
                 FROM    projects
                 WHERE   projects.client_id = posts.client_id);

Uma razão para usar isso em vez da junção é que a DELETEwith JOINproíbe o uso de LIMIT. Se você deseja excluir os blocos para não produzir bloqueios de tabela completos, adicione LIMITeste DELETE WHERE EXISTSmétodo.

Jim Clouse
fonte
1
Esta consulta pode ser escrita com "aliases"? Não está muito claro na sintaxe como postsEXISTS () é o mesmo de postsonde as linhas são excluídas. (IMHO de qualquer maneira)
MattBianco
Eu ouvi você, mas aliases não são permitidos na tabela para excluir. As "postagens" na subconsulta devem ser o nome completo da tabela, o que significa que, se você quiser reutilizar essa tabela na cláusula From da sub-seleção, será necessário o alias nela.
perfil completo de Jim Clouse
1
Isso funciona:DELETE p FROM posts p WHERE EXISTS ( SELECT 1 FROM projects WHERE projects.client_id = p.client_id);
MattBianco
4
mysql> INSERT INTO tb1 VALUES(1,1),(2,2),(3,3),(6,60),(7,70),(8,80);

mysql> INSERT INTO tb2 VALUES(1,1),(2,2),(3,3),(4,40),(5,50),(9,90);

DELETE registros de uma tabela:

mysql> DELETE tb1 FROM tb1,tb2 WHERE tb1.id= tb2.id;

EXCLUIR REGISTROS DE ambas as tabelas:

mysql> DELETE tb2,tb1 FROM tb2 JOIN tb1 USING(id);
zloctb
fonte
1

Se a junção não funcionar, você pode tentar esta solução. É para excluir registros órfãos de t1 quando não estiver usando chaves estrangeiras + condição específica. Ou seja, ele exclui registros da tabela1, que possuem o campo "código" vazio e que não possuem registros na tabela2, correspondendo pelo campo "nome".

delete table1 from table1 t1 
    where  t1.code = '' 
    and 0=(select count(t2.name) from table2 t2 where t2.name=t1.name);
Kristjan Adojaan
fonte
0

Tente isso,

DELETE posts.*
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id
Silambarasan
fonte
-3

- Observe que você não pode usar um alias sobre a tabela em que precisa excluir

DELETE tbl_pagos_activos_usuario
FROM tbl_pagos_activos_usuario, tbl_usuarios b, tbl_facturas c
Where tbl_pagos_activos_usuario.usuario=b.cedula
and tbl_pagos_activos_usuario.cod=c.cod
and tbl_pagos_activos_usuario.rif=c.identificador
and tbl_pagos_activos_usuario.usuario=c.pay_for
and tbl_pagos_activos_usuario.nconfppto=c.nconfppto
and NOT ISNULL(tbl_pagos_activos_usuario.nconfppto)
and c.estatus=50
Hernan Torres
fonte