833 Stimmen

MySQL-Fehler 1093 - In der FROM-Klausel kann die Zieltabelle für die Aktualisierung nicht angegeben werden

Ich habe eine Tabelle story_category in meiner Datenbank mit fehlerhaften Einträgen. Die nächste Abfrage gibt die beschädigten Einträge zurück:

SELECT * 
FROM  story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
       story_category ON category_id=category.id);

Ich habe versucht, sie zu löschen und auszuführen:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category 
      INNER JOIN story_category ON category_id=category.id);

Aber ich erhalte den nächsten Fehler:

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

Wie kann ich dieses Problem lösen?

5 Stimmen

3 Stimmen

Es sieht so aus, als ob der Feature Request im MySQL Bug Tracker hier ist: keine Aktualisierung einer Tabelle und Auswahl aus derselben Tabelle in einer Unterabfrage möglich

46voto

NexusRex Punkte 2042
DELETE FROM story_category
WHERE category_id NOT IN (
    SELECT cid FROM (
        SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id
    ) AS c
)

3 Stimmen

Können Sie erklären, warum das funktioniert, warum es reicht, eine weitere Ebene zu verschachteln? Diese Frage wurde bereits als Kommentar zur Frage von @EkoNoval gestellt, aber niemand hat darauf geantwortet. Vielleicht können Sie helfen.

1 Stimmen

@AkshayArora, Lesen Sie den Teil unter der Überschrift "Vielleicht können Sie die Tabelle einfach mit sich selbst verbinden" in der Antwort von @Cheekysoft. Er sagte UPDATE tbl AS a INNER JOIN tbl AS b ON .... SET a.col = b.col - Dies würde funktionieren, da hier ein anderer Alias für dieselbe Tabelle verwendet wird. Ähnlich in der Antwort von @NexusRex die erste SELECT Abfrage fungiert als abgeleitete Tabelle, in die story_category wird zum zweiten Mal verwendet. Der im OP erwähnte Fehler sollte hier also nicht auftreten, richtig?

20voto

Doin Punkte 6782

Für die spezifische Abfrage, die der OP zu erreichen versucht, ist der ideale und effizienteste Weg, dies zu tun NICHT eine Unterabfrage überhaupt zu verwenden.

Hier sind die LEFT JOIN Versionen der beiden Abfragen des Auftraggebers:

SELECT s.* 
FROM story_category s 
LEFT JOIN category c 
ON c.id=s.category_id 
WHERE c.id IS NULL;

Nota: DELETE s schränkt Löschvorgänge auf den story_category Tisch.
Dokumentation

DELETE s 
FROM story_category s 
LEFT JOIN category c 
ON c.id=s.category_id 
WHERE c.id IS NULL;

1 Stimmen

Ich bin überrascht, dass dies nicht mehr Stimmen erhält. Es sollte auch beachtet werden, dass die Multi-Table-Syntax auch mit UPDATE Anweisungen und verbundene Unterabfragen. Ermöglicht die Durchführung von LEFT JOIN ( SELECT ... ) im Gegensatz zu WHERE IN( SELECT ... ) Dadurch wird die Implementierung für viele Anwendungsfälle nützlich.

15voto

sactiw Punkte 20857

Dies ist, was ich für die Aktualisierung einer Prioritätsspalte Wert um 1, wenn es > = 1 in einer Tabelle und in seiner WHERE-Klausel mit einer Unterabfrage auf der gleichen Tabelle, um sicherzustellen, dass mindestens eine Zeile enthält Priorität = 1 (denn das war die Bedingung, die während der Durchführung von Update überprüft werden):

UPDATE My_Table
SET Priority=Priority + 1
WHERE Priority >= 1
AND (SELECT TRUE FROM (SELECT * FROM My_Table WHERE Priority=1 LIMIT 1) as t);

Ich weiß, es ist ein bisschen hässlich, aber es funktioniert gut.

2 Stimmen

@anonymous_reviewer: Wenn Sie [-1] oder sogar [+1] für einen Kommentar vergeben, geben Sie bitte auch an, warum Sie das getan haben. Danke!!!

1 Stimmen

-1, weil dies nicht korrekt ist. Sie können nicht die gleiche Tabelle ändern, die Sie in der SELECT-Anweisung verwenden.

1 Stimmen

@Chris Ich habe es mit MySQL verifiziert und es funktioniert bei mir einwandfrei, also bitte ich Sie, es auf Ihrer Seite zu verifizieren und dann zu behaupten, dass es richtig oder falsch ist. Danke!!!

9voto

S.Roshanth Punkte 1479

Der einfachste Weg, dies zu tun, ist die Verwendung eines Tabellenalias, wenn Sie sich auf die übergeordnete Abfragetabelle innerhalb der Unterabfrage beziehen.

Beispiel:

insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));

Ändern Sie es in:

insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P));

5voto

YonahW Punkte 15040

Sie könnten die IDs der gewünschten Zeilen in eine temporäre Tabelle einfügen und dann alle in dieser Tabelle gefundenen Zeilen löschen.

das könnte das sein, was @Cheekysoft meinte, als er es in zwei Schritten machte.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X