SQL DELETE mit JOIN einer anderen Tabelle für die WHERE-Bedingung

72

Ich muss Zeilen löschen guide_category, die keine Beziehung zur guideTabelle haben (tote Beziehungen).

Folgendes möchte ich tun, aber es funktioniert natürlich nicht.

DELETE FROM guide_category AS pgc 
 WHERE pgc.id_guide_category IN (SELECT id_guide_category 
                                   FROM guide_category AS gc
                              LEFT JOIN guide AS g ON g.id_guide = gc.id_guide
                                  WHERE g.title IS NULL)

Error:

Sie können die Zieltabelle 'guide_category' für die Aktualisierung in der FROM-Klausel nicht angeben

hsz
quelle
1
Dies liegt an einer unangenehmen Einschränkung in MySQL. Siehe Quassnois Antwort - er hat die richtige Lösung, um dies anzugehen.
Roland Bouman

Antworten:

107

Ermöglicht aufgrund der Probleme bei der Sperrimplementierung MySQLkeine Referenzierung der betroffenen Tabelle mit DELETEoder UPDATE.

Sie müssen JOINstattdessen hier ein machen :

DELETE  gc.*
FROM    guide_category AS gc 
LEFT JOIN
        guide AS g 
ON      g.id_guide = gc.id_guide
WHERE   g.title IS NULL

oder verwenden Sie einfach ein NOT IN:

DELETE  
FROM    guide_category AS gc 
WHERE   id_guide NOT IN
        (
        SELECT  id_guide
        FROM    guide
        )
Quassnoi
quelle
15
Wenn Sie TSQL verwenden, verwenden Sie DELETE gcanstelle vonDELETE gc.*
Gezim
4
Für MySQL> 5.0 ist es auch DELETE gcanstelle vongc.*
Daniel W.
Aber welches ist schneller?
Duleshi
@duleshi: wenn richtig indiziert, das gleiche.
Quassnoi
@duleshi: Abhängig von Ihrer Datenbank kann eine dramatisch schneller sein als die andere. Nach meiner Erfahrung ist das LEFT JOINmit IS NULLschnell, das NOT INist langsam. Das war eine Postgres-Datenbank, auch wenn alle Indizes vorhanden waren.
Michael Piefel
9

Ich denke, Ihrer Beschreibung nach würde Folgendes ausreichen:

DELETE FROM guide_category 
WHERE id_guide NOT IN (SELECT id_guide FROM guide)

Ich gehe davon aus, dass die beteiligten Tabellen keine Einschränkungen hinsichtlich der referenziellen Integrität aufweisen.

Dolch
quelle
Dies wird ein bisschen langsam sein, da es eine (SELECT id_guide FROM Anleitung) für jeden Eintrag ausführt
Toumi
Das hängt eigentlich davon ab, @Toumi. Der Abfrageplaner / -optimierer kann hier viel hinter den Kulissen tun.
Dirk
4

Probieren Sie diese SQL-Beispielskripte aus, um das Verständnis zu erleichtern.

CREATE TABLE TABLE1 (REFNO VARCHAR(10))
CREATE TABLE TABLE2 (REFNO VARCHAR(10))

--TRUNCATE TABLE TABLE1
--TRUNCATE TABLE TABLE2

INSERT INTO TABLE1 SELECT 'TEST_NAME'
INSERT INTO TABLE1 SELECT 'KUMAR'
INSERT INTO TABLE1 SELECT 'SIVA'
INSERT INTO TABLE1 SELECT 'SUSHANT'

INSERT INTO TABLE2 SELECT 'KUMAR'
INSERT INTO TABLE2 SELECT 'SIVA'
INSERT INTO TABLE2 SELECT 'SUSHANT'

SELECT * FROM TABLE1
SELECT * FROM TABLE2

DELETE T1 FROM TABLE1 T1 JOIN TABLE2 T2 ON T1.REFNO = T2.REFNO

Ihr Fall ist:

   DELETE pgc
     FROM guide_category pgc 
LEFT JOIN guide g
       ON g.id_guide = gc.id_guide 
    WHERE g.id_guide IS NULL
user2384628
quelle
1
Das ist die Antwort. einfach und solide. gut gemacht, Sir
NikosKeyz
@NikosKeyz Das ist genau die gleiche Antwort wie die akzeptierte Antwort, nicht wahr?
sstn
@sstn nein. Die akzeptierte Antwort hat bei mir nicht funktioniert. Dies ist die beste Antwort für mich.
NikosKeyz
-3

Wie wäre es mit:

DELETE guide_category  
  WHERE id_guide_category IN ( 

        SELECT id_guide_category 
          FROM guide_category AS gc
     LEFT JOIN guide AS g 
            ON g.id_guide = gc.id_guide
         WHERE g.title IS NULL

  )
Philippe Leybaert
quelle
Dies ist die ursprüngliche Abfrage und hat genau das gleiche Problem, auf die ursprüngliche Tabelle in einem abgeleiteten Tabellenausdruck zu verweisen.
Siride