it-swarm.com.de

MySQL DELETE FROM mit Unterabfrage als Bedingung

Ich versuche eine Abfrage wie diese zu machen:

DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (
    SELECT DISTINCT(th1.tid)
    FROM term_hierarchy AS th1
    INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
    WHERE th1.parent = 1015
);

Wie Sie wahrscheinlich sagen können, möchte ich die übergeordnete Relation zu 1015 löschen, wenn dasselbe Tid andere Eltern hat. Das ergibt jedoch einen Syntaxfehler:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS th
WHERE th.parent = 1015 AND th.tid IN (
  SELECT DISTINCT(th1.tid)
  FROM ter' at line 1

Ich habe die Dokumentation überprüft und die Unterabfrage selbst ausgeführt, und es scheint alles auszuprobieren. Kann jemand herausfinden, was hier los ist?

Update : Wie unten angegeben, erlaubt MySQL nicht, dass die Tabelle, aus der Sie löschen, in einer Unterabfrage für die Bedingung verwendet wird.

68
mikl

Sie können keine Zieltabelle zum Löschen angeben.

Eine Problemumgehung

create table term_hierarchy_backup (tid int(10)); <- check data type

insert into term_hierarchy_backup 
SELECT DISTINCT(th1.tid)
FROM term_hierarchy AS th1
INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th1.parent = 1015;

DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (select tid from term_hierarchy_backup);
32
ajreal

Für andere, die diese Frage bei der Verwendung einer Unterabfrage löschen möchten, gebe ich Ihnen dieses Beispiel, um MySQL zu überlisten (selbst wenn einige Leute meinen, dass dies nicht möglich ist):

DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
             FROM tableE
             WHERE arg = 1 AND foo = 'bar');

gibt dir einen Fehler:

ERROR 1093 (HY000): You can't specify target table 'e' for update in FROM clause

Jedoch diese Abfrage:

DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
             FROM (SELECT id
                   FROM tableE
                   WHERE arg = 1 AND foo = 'bar') x);

wird gut funktionieren:

Query OK, 1 row affected (3.91 sec)

Packen Sie Ihre Unterabfrage in eine zusätzliche Unterabfrage (hier mit dem Namen x) ein, und MySQL erledigt das, was Sie möchten.

225
CodeReaper

Der Alias ​​sollte nach dem Schlüsselwort DELETE eingefügt werden:

DELETE th
FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN 
(
    SELECT DISTINCT(th1.tid)
    FROM term_hierarchy AS th1
    INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
    WHERE th1.parent = 1015
);
32
James Wiseman

Sie müssen in der delete -Anweisung erneut auf den Alias ​​verweisen, z.

DELETE th FROM term_hierarchy AS th
....

Wie hier in MySQL-Dokumenten beschrieben.

7
JNK

Ich ging das etwas anders an und es funktionierte für mich.

Ich musste secure_links aus meiner Tabelle entfernen, die auf die conditions-Tabelle verwies, in der keine Bedingungszeilen mehr vorhanden waren. Grundsätzlich ein Housekeeping-Skript. Dies gab mir den Fehler - Sie können keine Zieltabelle zum Löschen angeben.

Auf der Suche nach Inspiration hierher kam ich mit der untenstehenden Abfrage und sie funktioniert gut .. __ Dies ist so, weil sie eine temporäre Tabelle sl1 erstellt, die als Referenz für DELETE verwendet wird. 

DELETE FROM `secure_links` WHERE `secure_links`.`link_id` IN 
            (
            SELECT
                `sl1`.`link_id` 
            FROM 
                (
                SELECT 

                    `sl2`.`link_id` 

                FROM 
                    `secure_links` AS `sl2` 
                    LEFT JOIN `conditions` ON `conditions`.`job` = `sl2`.`job` 

                WHERE 

                    `sl2`.`action` = 'something' AND 
                    `conditions`.`ref` IS NULL 
                ) AS `sl1`
            )

Funktioniert bei mir.

6
Darren Edwards

Ist die "in" -Klausel nicht in delete, wo extrem ineffizient, wenn eine große Anzahl von Werten von der Unterabfrage zurückgegeben wird? Nicht sicher, warum Sie sich nicht einfach nach innen (oder nach rechts) gegen die ursprüngliche Tabelle aus der Unterabfrage der ID löschen lassen möchten, statt uns das "in (Unterabfrage)".

DELETE T FROM Target AS T
RIGHT JOIN (full subquery already listed for the in() clause in answers above) ` AS TT ON (TT.ID = T.ID)

Und vielleicht wird darauf in "MySQL nicht erlaubt" geantwortet, aber es funktioniert gut für mich VORGESTELLT Ich vergewissere mich, dass Sie vollständig klarstellen, was gelöscht werden soll (DELETE T FROM Target AS T). Mit Join in MySQL löschen klärt das DELETE/JOIN-Problem.

3
Jeff

Wenn Sie dies mit zwei Abfragen durchführen möchten, können Sie immer etwas Ähnliches tun:

1) nimm IDs aus der Tabelle mit:

SELECT group_concat(id) as csv_result FROM your_table WHERE whatever = 'test' ...

Kopieren Sie dann das Ergebnis mit der Maus/Tastatur oder der Programmiersprache nach XXX:

2) DELETE FROM your_table WHERE id IN ( XXX )

Vielleicht könnten Sie dies in einer Abfrage tun, aber das ist mir lieber.

1
TomoMiha

@CodeReaper, @BennyHill: Es funktioniert wie erwartet. 

Ich frage mich jedoch, wie komplex es ist, Millionen Zeilen in der Tabelle zu haben. Anscheinend brauchte es etwa 5ms, um 5k Datensätze in einer korrekt indizierten Tabelle zu haben. 

Meine Anfrage:

SET status = '1'
WHERE id IN (
    SELECT id
    FROM (
      SELECT c2.id FROM clusters as c2
      WHERE c2.assign_to_user_id IS NOT NULL
        AND c2.id NOT IN (
         SELECT c1.id FROM clusters AS c1
           LEFT JOIN cluster_flags as cf on c1.last_flag_id = cf.id
           LEFT JOIN flag_types as ft on ft.id = cf.flag_type_id
         WHERE ft.slug = 'closed'
         )
      ) x)```

Or is there something we can improve on my query above?
0
rcadhikari