Supprimer avec Join dans MySQL

501

Voici le script pour créer mes tables:

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)
);

Dans mon code PHP, lors de la suppression d'un client, je souhaite supprimer tous les articles des projets:

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

La table des publications n'a pas de clé étrangère client_id, seulementproject_id . Je souhaite supprimer les articles des projets qui ont été approuvés client_id.

Cela ne fonctionne pas pour le moment car aucun message n'est supprimé.

GeekJock
la source
10
Je pense que la réponse de Yehosef devrait être la réponse acceptée, car il utilise Join comme vous l'avez demandé et qu'il fonctionne mieux que d'utiliser une clause IN comme le propose le yukondude ...
Gerardo Grignoli
2
Le modèle préféré est un DELETE posts FROM posts JOIN projects ..., plutôt qu'un IN (subquery)modèle. (La réponse de Yehosef donne un exemple du modèle préféré.)
spencer7593
@GerardoGrignoli, il fonctionne mieux pour un moteur ou une version particulière de MySQL? Il n'y a aucune raison pour que les deux requêtes fonctionnent différemment, car AFAIK elles sont identiques. Bien sûr, si j'avais un nickel à chaque fois, mon optimiseur de requête faisait quelque chose de stupide ....
Paul Draper
Vous pouvez également utiliser aliasle nom de la table et l'utiliser.
biniam

Réponses:

1254

Il vous suffit de spécifier que vous souhaitez supprimer les entrées du poststableau:

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

EDIT: Pour plus d'informations, vous pouvez voir cette réponse alternative

Yehosef
la source
117
Il convient de noter que c'est la bonne réponse car la jointure vous oblige à utiliser "DELETE posts FROM posts" au lieu des "DELETE FROM posts" normaux, car le tableau à supprimer n'est plus sans ambiguïté. Merci!
siannopollo
8
Notez que vous ne pouvez pas utiliser la méthode 'as' ici, par exemple les projets de jointure interne comme p sur p.project_id ...
zzapper
14
En fait, vous pouvez utiliser un alias pour les tables jointes, mais pas pour la table principale (publications). "SUPPRIMER les articles des articles INNER JOIN projets p ON p.project_id = posts.project_id"
Weboide
14
c'est la meilleure réponse car vous pouvez même supprimer des deux tables en une seule actionDELETE posts , projects FROM posts INNER JOIN projects ON projects.project_id = posts.project_id WHERE projects.client_id = :client_id
Developerium
84

Puisque vous sélectionnez plusieurs tables, la table à supprimer n'est plus sans ambiguïté. Vous devez sélectionner :

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

Dans ce cas, table_name1et table_name2sont la même table, donc cela fonctionnera:

DELETE projects FROM posts INNER JOIN [...]

Vous pouvez même supprimer des deux tableaux si vous souhaitez:

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

Notez que order byet limit ne fonctionnent pas pour les suppressions multi-tables .

Sachez également que si vous déclarez un alias pour une table, vous devez utiliser l'alias lorsque vous vous référez à la table:

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

Les contributions des Carpetsmoker et etc .

Pacerier
la source
3
Si vous faites une meilleure réponse - au moins, vous pourriez rendre le SQL plus lisible. Toutes les autres références SQL dans cette question ont des mots-clés en majuscule (sauf une avec 0 votes). Je ne sais pas pourquoi vous avez annulé mes modifications.
Yehosef
3
@Yehosef, il y a un groupe de personnes qui trouvent les CAPS vraiment éclatants. Je crois que je ne suis pas le seul, j'ai vu pas mal de gens aussi en style minuscule.
Pacerier
1
assez juste - je respecte votre droit d'écrire votre réponse dans le style que vous aimez;)
Yehosef
7
Pour ajouter à la discussion sur les majuscules / pas de majuscules, il est vrai que vous pouvez utiliser le style que vous aimez, mais dans votre réponse, vous mélangez en fait des styles où vous le souhaitez - le ONest en majuscule. Pour les développeurs moins expérimentés, cela peut signifier qu'il est OK d'être désordonné et incohérent en termes de style.
Teinte
16
LES MOTS-CLÉS CAPS ne sont pas flagrants. ils rendent les requêtes lisibles;)
Sachem
50

Ou la même chose, avec une syntaxe légèrement différente (plus conviviale pour l'OMI):

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

BTW, avec mysql à l'aide de jointures est presque toujours un moyen plus rapide que les sous-requêtes ...

ivanhoe
la source
Que signifie USING?
CMCDragonkai
1
Bonne explication de USING: stackoverflow.com/questions/11366006/mysql-on-vs-using
bigtex777
10
@ bigtex777: Veuillez noter que le mot clé USING dans les instructions SELECT a peu à voir avec le même mot clé dans une instruction DELETE. Dans SELECTs, il spécifie la liste des colonnes à joindre, tandis que dans DELETEs, c'est une liste de toutes les tables dans une jointure
ivanhoe
42

Vous pouvez également utiliser ALIAS comme cela, cela fonctionne, il suffit de l'utiliser sur ma base de données! t la table doit être supprimée!

DELETE t FROM posts t
INNER JOIN projects p ON t.project_id = p.project_id
AND t.client_id = p.client_id
Propriété Espagne
la source
1
ceci est utile sur les jointures de clés composées pour éviter de répéter les noms de table
Marquez
1
"En fait, vous pouvez utiliser un alias pour les tables jointes, mais pas pour la table principale (messages). 'DELETE posts from posts INNER JOIN projects p ON p.project_id = posts.project_id'" - @ Weboide
Jeaf Gilbert
2
En fait (en citant dev.mysql.com/doc/refman/5.0/en/delete.html ) "Si vous déclarez un alias pour une table, vous devez utiliser l'alias lorsque vous vous référez à la table: DELETE t1 FROM test AS t1, test2 WHERE ... "donc l'utilisation d'un alias est très bien.
Peter Bowers
25

Je suis plus habitué à la solution de sous-requête, mais je ne l'ai pas essayé dans MySQL:

DELETE  FROM posts
WHERE   project_id IN (
            SELECT  project_id
            FROM    projects
            WHERE   client_id = :client_id
        );
yukondude
la source
85
Vous devriez vraiment éviter d'utiliser le mot clé IN dans SQL (même s'il est généralement plus facile à comprendre pour les débutants) et utiliser JOIN à la place (lorsque cela est possible), car les sous-requêtes rendent généralement les choses beaucoup plus lentes.
user276648
14
Cela a tendance à planter la base de données lorsqu'il y a un grand nombre de lignes retournées par la sous-requête. Il est également extrêmement lent.
Raj
2
@yukondude En effet, "IN" est beaucoup plus facile à comprendre que "JOIN" au début, et c'est pourquoi les gens qui ne sont pas vraiment familiers avec SQL finiront par écrire "IN" partout, alors qu'ils pourraient utiliser "JOIN" qui fonctionne mieux ( ou un whooole beaucoup mieux, selon la requête). Je me souviens il y a plusieurs années, presque toutes mes requêtes SQL seraient réécrites par quelqu'un qui savait réellement écrire de bonnes requêtes. C'est pourquoi j'ai ajouté le commentaire pour éviter "IN", afin que les gens sachent que si possible, ils devraient éviter de l'utiliser.
user276648
10
La raison pour laquelle je suis venu sur cette page est que la requête que j'ai écrite avec une instruction IN était lente. Évitez certainement la réponse acceptée ici.
MikeKulls
4
Aussi ancienne que soit cette question, il est important de savoir POURQUOI vous devez utiliser JOIN au lieu de IN. Lorsque cette condition où s'exécute sur une ligne, il va exécuter cette requête dans IN. Cela signifie que s'il y a 100 lignes qui doivent être vérifiées par rapport à WHERE, cette sous-requête va être exécutée 100 fois. Alors qu'un JOIN ne s'exécutera qu'une fois. Donc, à mesure que votre base de données devient de plus en plus grande, cette requête va prendre de plus en plus de temps pour se terminer. @markus simplement parce que quelque chose n'est pas critique ne signifie pas que vous devez écrire du mauvais code. L'écrire un peu mieux vous fera économiser beaucoup de temps et de maux de tête à l'avenir. :)
RisingSun
11

Enregistrements DELETE MySQL avec JOIN

Vous utilisez généralement INNER JOIN dans l'instruction SELECT pour sélectionner des enregistrements d'une table qui ont des enregistrements correspondants dans d'autres tables. Nous pouvons également utiliser la clause INNER JOIN avec l'instruction DELETE pour supprimer les enregistrements d'une table et également les enregistrements correspondants dans d'autres tables, par exemple, pour supprimer les enregistrements des tables T1 et T2 qui remplissent une condition particulière, vous utilisez l'instruction suivante:

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

Notez que vous placez les noms de table T1 et T2 entre DELETE et FROM. Si vous omettez la table T1, l'instruction DELETE supprime uniquement les enregistrements de la table T2 et si vous omettez la table T2, seuls les enregistrements de la table T1 sont supprimés.

La condition de jointure T1.key = T2.key spécifie les enregistrements correspondants dans la table T2 qui doivent être supprimés.

La condition de la clause WHERE spécifie les enregistrements du T1 et du T2 qui doivent être supprimés.

Aman Garg
la source
11

Suppression d'une table unique:

Pour supprimer des entrées du poststableau:

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;

Pour supprimer des entrées du projectstableau:

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;

Pour supprimer des entrées du clientstableau:

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;

Suppression de plusieurs tables:

Afin de supprimer des entrées de plusieurs tables des résultats joints, vous devez spécifier les noms de table après DELETEcomme liste séparée par des virgules:

Supposons que vous voulez supprimer des entrées de tous les trois tableaux ( posts, projects, clients) pour un client particulier:

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
la source
7

Essayez comme ci-dessous:

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

Une autre méthode de suppression à l'aide d'une sous-sélection qui est meilleure que l'utilisation INseraitWHERE EXISTS

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

L'une des raisons d'utiliser ceci au lieu de la jointure est qu'un DELETEavec JOINinterdit l'utilisation de LIMIT. Si vous souhaitez supprimer des blocs afin de ne pas produire de verrous de table complets, vous pouvez ajouter LIMITutiliser cette DELETE WHERE EXISTSméthode.

Jim Clouse
la source
1
Cette requête peut-elle être écrite avec des "alias"? D'après la syntaxe, il n'est pas très clair en quoi postsEXISTS () est identique à postsla suppression des lignes. (À
mon humble avis
Je vous entends, mais les alias ne sont pas autorisés dans le tableau à supprimer. Les "publications" dans la sous-requête doivent être le nom complet de la table, ce qui signifie que si vous souhaitez réutiliser cette table dans votre clause de sous-sélection de, vous devrez l'aliaser à cet endroit.
Jim Clouse du
1
Cela fonctionne: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);

SUPPRIMER les enregistrements d'une table:

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

SUPPRIMER LES ENREGISTREMENTS DES DEUX tables:

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

Si join ne fonctionne pas pour vous, vous pouvez essayer cette solution. Il sert à supprimer les enregistrements orphelins de t1 lorsque vous n'utilisez pas de clés étrangères + condition Where spécifique. C'est-à-dire qu'il supprime les enregistrements de la table1, qui ont le champ vide "code" et qui n'ont pas d'enregistrements dans la table2, correspondant par le champ "nom".

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

Essaye ça,

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

- Notez que vous ne pouvez pas utiliser d'alias sur la table où vous devez supprimer

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
la source