Löschen mit Join in MySQL

501

Hier ist das Skript zum Erstellen meiner Tabellen:

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

In meinem PHP-Code möchte ich beim Löschen eines Clients alle Projektbeiträge löschen:

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

Die Beiträge Tabelle nicht über einen Fremdschlüssel client_idnur project_id. Ich möchte die Beiträge in Projekten löschen, die bestanden haben client_id.

Dies funktioniert momentan nicht, da keine Beiträge gelöscht werden.

GeekJock
quelle
10
Ich denke, Yehosef Antwort sollte die akzeptierte sein, da er Join verwendet, wie Sie gefragt haben, und dass es besser funktioniert als die Verwendung einer IN-Klausel, wie von Yukondude vorgeschlagen ...
Gerardo Grignoli
2
Das bevorzugte Muster ist DELETE posts FROM posts JOIN projects ...eher ein als ein IN (subquery)Muster. (Die Antwort von Yehosef gibt ein Beispiel für das bevorzugte Muster.)
spencer7593
@GerardoGrignoli, es ist besser für eine bestimmte Engine oder Version von MySQL? Es gibt keinen Grund, warum die beiden Abfragen unterschiedlich ausgeführt werden sollten, da sie nach AFAIK identisch sind. Natürlich, wenn ich jedes Mal einen Nickel hatte, wenn mein Abfrageoptimierer etwas Dummes tat ...
Paul Draper
Sie können auch aliasden Tabellennamen verwenden und diesen verwenden.
Biniam

Antworten:

1254

Sie müssen nur angeben, dass Sie die Einträge aus der postsTabelle löschen möchten :

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

BEARBEITEN: Weitere Informationen finden Sie in dieser alternativen Antwort

Yehosef
quelle
117
Es ist zu beachten, dass dies die richtige Antwort ist, da der Join Sie zwingt, "DELETE FROM FROM posts" anstelle von "DELETE FROM posts" zu verwenden, da die zu löschende Tabelle nicht mehr eindeutig ist. Vielen Dank!
Siannopollo
8
Beachten Sie, dass Sie hier nicht die 'as'-Methode verwenden können, z. B. Inner Join-Projekte als p auf p.project_id ...
zzapper
14
Eigentlich können Sie einen Alias ​​für verknüpfte Tabellen verwenden, aber nicht für die Haupttabelle (Beiträge). "Beiträge von Beiträgen löschen INNER JOIN-Projekte p ON p.project_id = posts.project_id"
Weboide
14
Dies ist die beste Antwort, da Sie sogar in einer Aktion aus beiden Tabellen löschen könnenDELETE posts , projects FROM posts INNER JOIN projects ON projects.project_id = posts.project_id WHERE projects.client_id = :client_id
Developerium
84

Da Sie mehrere Tabellen auswählen, ist die zu löschende Tabelle nicht mehr eindeutig. Sie müssen auswählen :

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

In diesem Fall table_name1und table_name2ist der gleiche Tisch, so wird diese Arbeit:

DELETE projects FROM posts INNER JOIN [...]

Sie können sogar aus beiden Tabellen löschen, wenn Sie möchten:

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

Beachten Sie dies order byund limit funktionieren Sie nicht für Löschvorgänge mit mehreren Tabellen .

Beachten Sie außerdem, dass Sie beim Deklarieren eines Alias ​​für eine Tabelle den Alias ​​verwenden müssen, wenn Sie auf die Tabelle verweisen:

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

Beiträge aus Carpetsmoker und etc .

Pacerier
quelle
3
Wenn Sie eine bessere Antwort geben, können Sie zumindest die SQL besser lesbar machen. Alle anderen SQL-Referenzen in dieser Frage haben Schlüsselwörter in Großbuchstaben geschrieben (mit Ausnahme einer mit 0 Stimmen). Ich bin mir nicht sicher, warum Sie meine Änderungen rückgängig gemacht haben.
Yehosef
3
@ Yehosef, Es gibt eine Gruppe von Leuten, die die CAPS wirklich krass finden. Ich glaube, ich bin nicht der einzige, ich habe auch einige Leute gesehen, die Kleinbuchstaben geschrieben haben.
Pacerier
1
fair genug - ich respektiere dein Recht, deine Antwort in dem Stil zu schreiben, den du
Yehosef
7
Um die Diskussion über Caps / No Caps zu erweitern, können Sie zwar einen beliebigen Stil verwenden, aber in Ihrer Antwort mischen Sie tatsächlich Stile, die Sie für zweckmäßig halten - der ONwird groß geschrieben. Für weniger erfahrene Entwickler kann dies bedeuten, dass es in Ordnung ist, chaotisch und in Bezug auf den Stil inkonsistent zu sein.
Schatten
16
CAPS KEYWORDS sind nicht grell. sie machen die Fragen lesbar;)
Sachem
50

Oder dasselbe mit einer etwas anderen (IMO-freundlicheren) Syntax:

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

Übrigens, mit MySQL ist die Verwendung von Joins fast immer viel schneller als Unterabfragen ...

ivanhoe
quelle
Was bedeutet USING?
CMCDragonkai
1
Gute Erklärung für USING: stackoverflow.com/questions/11366006/mysql-on-vs-using
bigtex777
10
@ bigtex777: Bitte beachten Sie, dass das Schlüsselwort USING in SELECT-Anweisungen wenig mit demselben Schlüsselwort in einer DELETE-Anweisung zu tun hat. In SELECTs gibt es die Liste der Spalten an, denen beigetreten werden soll, während es in DELETEs eine Liste aller Tabellen in einem Join ist
ivanhoe
42

Sie können ALIAS auch so verwenden, dass es funktioniert. Verwenden Sie es einfach in meiner Datenbank! t ist die Tabelle, aus der gelöscht werden muss!

DELETE t FROM posts t
INNER JOIN projects p ON t.project_id = p.project_id
AND t.client_id = p.client_id
Eigentum Spanien
quelle
1
Dies ist nützlich bei zusammengesetzten Schlüsselverknüpfungen, um zu vermeiden, dass die Tabellennamen wiederholt werden
Marquez
1
"Eigentlich können Sie einen Alias ​​für verknüpfte Tabellen verwenden, aber nicht für die Haupttabelle (Beiträge). 'Beiträge von Beiträgen löschen INNER JOIN-Projekte p ON p.project_id = posts.project_id'" - @ Weboide
Jeaf Gilbert
2
Tatsächlich (zitiert aus dev.mysql.com/doc/refman/5.0/en/delete.html ) "Wenn Sie einen Alias ​​für eine Tabelle deklarieren, müssen Sie den Alias ​​verwenden, wenn Sie auf die Tabelle verweisen: DELETE t1 FROM test AS t1, test2 WHERE ... "Die Verwendung eines Alias ​​ist also in Ordnung.
Peter Bowers
25

Ich bin eher an die Unterabfragelösung gewöhnt, habe sie aber in MySQL nicht ausprobiert:

DELETE  FROM posts
WHERE   project_id IN (
            SELECT  project_id
            FROM    projects
            WHERE   client_id = :client_id
        );
Yukondude
quelle
85
Sie sollten die Verwendung des Schlüsselworts IN in SQL wirklich vermeiden (obwohl es für Anfänger normalerweise einfacher zu verstehen ist) und stattdessen JOIN verwenden (wenn möglich), da Unterabfragen die Dinge normalerweise viel langsamer machen.
user276648
14
Dies führt dazu, dass die Datenbank abstürzt, wenn eine große Anzahl von Zeilen von der Unterabfrage zurückgegeben wird. Es ist auch immens langsam.
Raj
2
@yukondude In der Tat ist "IN" viel einfacher zu verstehen als "JOIN" am 1. und deshalb schreiben Leute, die nicht wirklich mit SQL vertraut sind, überall "IN", während sie "JOIN" verwenden könnten, was eine bessere Leistung bringt ( oder ein whooole viel besser, je nach Abfrage). Ich erinnere mich, dass vor einigen Jahren fast alle meine SQL-Abfragen von jemandem umgeschrieben wurden, der tatsächlich wusste, wie man gute Abfragen schreibt. Deshalb habe ich den Kommentar hinzugefügt, um "IN" zu vermeiden, damit die Leute wissen, dass sie ihn nach Möglichkeit vermeiden sollten.
user276648
10
Der Grund, warum ich auf diese Seite gekommen bin, ist, dass die Abfrage, die ich mit einer IN-Anweisung geschrieben habe, hundeschwach war. Vermeiden Sie auf jeden Fall die hier akzeptierte Antwort.
MikeKulls
4
So alt diese Frage auch ist, es ist wichtig zu wissen, WARUM Sie JOIN anstelle von IN verwenden sollten. Wenn diese Bedingung in einer Zeile ausgeführt wird, wird diese Abfrage in IN ausgeführt. Das heißt, wenn es 100 Zeilen gibt, die mit diesem WHERE verglichen werden müssen, wird diese Unterabfrage 100 Mal ausgeführt. Während ein JOIN nur EINMAL ausgeführt wird. Wenn Ihre Datenbank also immer größer wird, wird es immer länger dauern, bis diese Abfrage abgeschlossen ist. @markus Nur weil etwas nicht kritisch ist, heißt das nicht, dass Sie schlechten Code schreiben sollten. Wenn Sie es ein wenig besser schreiben, sparen Sie in Zukunft viel Zeit und Kopfschmerzen. :)
RisingSun
11

MySQL DELETE zeichnet mit JOIN auf

Im Allgemeinen verwenden Sie INNER JOIN in der SELECT-Anweisung, um Datensätze aus einer Tabelle auszuwählen, die entsprechende Datensätze in anderen Tabellen enthalten. Wir können auch die INNER JOIN-Klausel mit der DELETE-Anweisung verwenden, um Datensätze aus einer Tabelle zu löschen, sowie die entsprechenden Datensätze in anderen Tabellen, z. B. um Datensätze aus T1- und T2-Tabellen zu löschen, die eine bestimmte Bedingung erfüllen, verwenden Sie die folgende Anweisung:

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

Beachten Sie, dass Sie die Tabellennamen T1 und T2 zwischen DELETE und FROM setzen. Wenn Sie die T1-Tabelle weglassen, löscht die DELETE-Anweisung nur Datensätze in der T2-Tabelle, und wenn Sie die T2-Tabelle weglassen, werden nur Datensätze in der T1-Tabelle gelöscht.

Die Verknüpfungsbedingung T1.key = T2.key gibt die entsprechenden Datensätze in der T2-Tabelle an, die gelöscht werden müssen.

Die Bedingung in der WHERE-Klausel gibt an, welche Datensätze in T1 und T2 gelöscht werden müssen.

Aman Garg
quelle
11

Löschen einer einzelnen Tabelle:

So löschen Sie Einträge aus der postsTabelle:

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;

So löschen Sie Einträge aus der projectsTabelle:

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;

So löschen Sie Einträge aus der clientsTabelle:

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;

Mehrere Tabellen löschen:

Um Einträge aus mehreren Tabellen aus den verknüpften Ergebnissen zu löschen, müssen Sie die Tabellennamen nach DELETEals durch Kommas getrennte Liste angeben :

Angenommen , Sie Einträge aus allen drei Tabellen löschen möchten ( posts, projects, clients) für einen bestimmten Client:

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
quelle
7

Versuchen Sie es wie folgt:

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

Eine andere Methode zum Löschen mit einer Unterauswahl, die besser ist als die Verwendung, INwäreWHERE EXISTS

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

Ein Grund, dies anstelle des Joins zu verwenden, ist, dass a DELETEwith JOINdie Verwendung von verbietet LIMIT. Wenn Sie in Blöcken löschen möchten, um keine vollständigen Tabellensperren zu erzeugen, können Sie LIMITdiese DELETE WHERE EXISTSMethode hinzufügen .

Jim Clouse
quelle
1
Kann diese Abfrage mit "Aliasen" geschrieben werden? Aus der Syntax geht nicht klar hervor, dass postsEXISTS () dasselbe ist posts, aus dem die Zeilen gelöscht werden. (IMHO sowieso)
MattBianco
Ich höre Sie, aber Aliase in der Tabelle dürfen nicht gelöscht werden. Die "Beiträge" in der Unterabfrage müssen den vollständigen Tabellennamen haben. Wenn Sie diese Tabelle in Ihrer Unterauswahl-From-Klausel wiederverwenden möchten, müssen Sie sie dort als Alias ​​verwenden.
Jim Clouse
1
Dies funktioniert: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);

Datensätze aus einer Tabelle löschen:

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

LÖSCHEN VON AUFZEICHNUNGEN AUS beiden Tabellen:

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

Wenn der Join für Sie nicht funktioniert, können Sie diese Lösung ausprobieren. Es dient zum Löschen verwaister Datensätze aus t1, wenn keine Fremdschlüssel verwendet werden + spezifische where-Bedingung. Das heißt, es löscht Datensätze aus Tabelle1, die ein leeres Feld "Code" haben und keine Datensätze in Tabelle2 haben, die mit dem Feld "Name" übereinstimmen.

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

Versuche dies,

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

- Beachten Sie, dass Sie keinen Alias ​​für die Tabelle verwenden können, in der Sie löschen müssen

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
quelle