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

957voto

Cheekysoft Punkte 34104

Aktualisierung: Diese Antwort behandelt die allgemeine Fehlerklassifizierung. Eine spezifischere Antwort darauf, wie die genaue Anfrage des Auftraggebers am besten zu behandeln ist, finden Sie in anderen Antworten auf diese Frage

In MySQL können Sie nicht die gleiche Tabelle ändern, die Sie im SELECT-Teil verwenden.
Dieses Verhalten ist dokumentiert unter: http://dev.mysql.com/doc/refman/5.6/en/update.html

Vielleicht können Sie die Tabelle einfach mit sich selbst verbinden

Wenn die Logik einfach genug ist, um die Abfrage umzugestalten, lassen Sie die Unterabfrage weg und verbinden Sie die Tabelle mit sich selbst, indem Sie geeignete Auswahlkriterien verwenden. Dadurch wird MySQL veranlasst, die Tabelle als zwei verschiedene Dinge zu betrachten, so dass destruktive Änderungen vorgenommen werden können.

UPDATE tbl AS a
INNER JOIN tbl AS b ON ....
SET a.col = b.col

Versuchen Sie alternativ, die Unterabfrage tiefer in eine from-Klausel zu schachteln ...

Wenn Sie die Unterabfrage unbedingt benötigen, gibt es eine Umgehungslösung, aber die ist hässlich aus mehreren Gründen, einschließlich Leistung:

UPDATE tbl SET col = (
  SELECT ... FROM (SELECT.... FROM) AS x);

Die verschachtelte Unterabfrage in der FROM-Klausel erzeugt eine implizit temporär Tabelle so dass sie nicht als dieselbe Tabelle gilt, die Sie aktualisieren.

... aber achten Sie auf den Abfrageoptimierer

Beachten Sie jedoch, dass von MySQL 5.7.6 und weiter, kann der Optimierer die Unterabfrage optimieren und Ihnen trotzdem den Fehler anzeigen. Glücklicherweise ist die optimizer_switch kann verwendet werden, um dieses Verhalten abzuschalten, obwohl ich dies nur als kurzfristige Lösung oder für kleine, einmalige Aufgaben empfehlen kann.

SET optimizer_switch = 'derived_merge=off';

Dank an Peter V. Mørch für diesen Ratschlag in den Kommentaren.

Die Beispieltechnik stammt von Baron Schwartz, ursprünglich veröffentlicht bei Nabble , hier paraphrasiert und erweitert.

1 Stimmen

Ich habe diese Antwort hochgestuft, weil ich Elemente löschen musste und keine Informationen aus einer anderen Tabelle erhalten konnte, sondern eine Unterabfrage aus derselben Tabelle durchführen musste. Da dies das ist, was oben erscheint, während ich nach dem Fehler google, den ich bekam, wäre dies die beste Antwort für mich und eine Menge Leute, die versuchen, zu aktualisieren, während sie eine Unterabfrage aus der gleichen Tabelle machen.

2 Stimmen

@Cheekysoft, Warum speichern Sie die Werte nicht stattdessen in Variablen?

1 Stimmen

@PeterV.Mørch Folgen mysqlserverteam.com/abgeleitete-tabellen-in-mysql-5-7 Wenn bestimmte Operationen durchgeführt werden, kann die Zusammenführung nicht stattfinden. Versehen Sie z.B. die abgeleitete Dummy-Tabelle mit einem LIMIT (bis zur Unwirksamkeit) und der Fehler wird nie auftreten. Das ist allerdings ziemlich hakelig und es besteht immer noch das Risiko, dass zukünftige Versionen von MySQL das Zusammenführen von Abfragen mit LIMIT doch noch unterstützen werden.

560voto

Yehor Punkte 5193

NexusRex sofern ein sehr gute Lösung zum Löschen mit Join aus derselben Tabelle.

Wenn Sie dies tun:

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

werden Sie eine Fehlermeldung erhalten.

Aber wenn Sie die Bedingung in ein weiteres Select einpacken:

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
)

würde es das Richtige tun!!

Erläuterung: Der Abfrageoptimierer führt eine abgeleitete Merge-Optimierung für die erste Abfrage (wodurch sie mit dem Fehler fehlschlägt), aber die zweite Abfrage qualifiziert sich nicht für die abgeleitete Merge-Optimierung . Daher ist der Optimierer gezwungen, die Unterabfrage zuerst auszuführen.

10 Stimmen

Vielleicht liegt es daran, dass ich heute in der Klemme stecke, aber das war die einfachste Antwort, auch wenn sie vielleicht nicht die "beste" ist.

4 Stimmen

Das hat super funktioniert, danke! Was ist also die Logik hier? Wenn es eine weitere Ebene verschachtelt ist, wird es vor dem äußeren Teil ausgeführt? Und wenn es nicht verschachtelt ist, dann versucht mySQL es auszuführen, nachdem das Löschen eine Sperre auf die Tabelle hat?

94 Stimmen

Dieser Fehler und die Lösung machen keinen logischen Sinn... aber es funktioniert. Manchmal frage ich mich, auf welchen Drogen die MySQL-Entwickler stehen...

122voto

El inner join in Ihrer Unterabfrage ist unnötig. Es sieht so aus, als wollten Sie die Einträge in story_category wo die category_id ist nicht in der category Tisch.

Stattdessen:

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

Tun Sie dies:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category);

7 Stimmen

Das sollte die erste Antwort sein! Streichen Sie vielleicht das erste "anstelle von".

2 Stimmen

Ich denke DISTINCT ist hier unnötig - für eine bessere Leistung ;).

2 Stimmen

Ich muss verrückt sein. Die Antwort ist dieselbe wie im Original.

121voto

Pratik Khadloya Punkte 11945

Kürzlich musste ich Datensätze in derselben Tabelle aktualisieren, die ich wie folgt erstellt habe:

UPDATE skills AS s, (SELECT id  FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development' 
WHERE s.id = p.id;

13 Stimmen

Kann dies nicht einfach so geschrieben werden UPDATE skills SET type='Development' WHERE type='Programming'; ? Das scheint keine Antwort auf die ursprüngliche Frage zu sein.

2 Stimmen

Scheint ein Overkill zu sein, @lilbyrdie hat recht - es könnte nur sein UPDATE skills SET type='Development' WHERE type='Programming'; . Ich verstehe nicht, warum so viele Menschen nicht darüber nachdenken, was sie tun...

4 Stimmen

Das ist die beste Antwort, IMHO. Die Syntax ist leicht zu verstehen, Sie können Ihre vorherige Aussage wiederverwenden und sie ist nicht auf einen superspezifischen Fall beschränkt.

107voto

Sequoya Punkte 994

Wenn Sie das nicht können

UPDATE table SET a=value WHERE x IN
    (SELECT x FROM table WHERE condition);

weil es sich um dieselbe Tabelle handelt, können Sie tricksen und tun:

UPDATE table SET a=value WHERE x IN
    (SELECT * FROM (SELECT x FROM table WHERE condition) as t)

[aktualisieren oder löschen oder was auch immer]

0 Stimmen

Die verständlichste und logischste Umsetzung aller oben genannten Antworten. Einfach und auf den Punkt gebracht.

2 Stimmen

Dies ist inzwischen Teil meines Arbeitsablaufs. Wenn Sie mit diesem Fehler nicht weiterkommen, gehen Sie zu dieser Antwort und beheben Sie die Frage. Danke!

0 Stimmen

Ich werde diesen Trick jetzt für alles anwenden. Unglaublich o_o

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