Ich habe eine Tabelle story_category
in meiner Datenbank mit beschädigten 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, indem ich Folgendes ausführte:
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 bekomme 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 das überwinden?
mysql
subquery
sql-delete
mysql-error-1093
Sergio del Amo
quelle
quelle
Antworten:
Update: Diese Antwort deckt die allgemeine Fehlerklassifizierung ab. Eine genauere Antwort darauf, wie die genaue Abfrage des OP am besten behandelt werden kann, finden Sie in anderen Antworten auf diese Frage
In MySQL können Sie nicht dieselbe 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 den Tisch einfach mit sich selbst verbinden
Wenn die Logik einfach genug ist, um die Abfrage neu zu gestalten, verlieren Sie die Unterabfrage und verbinden Sie die Tabelle unter Verwendung geeigneter Auswahlkriterien mit sich selbst. Dies führt dazu, dass MySQL die Tabelle als zwei verschiedene Dinge betrachtet, sodass destruktive Änderungen vorgenommen werden können.
Versuchen Sie alternativ, die Unterabfrage tiefer in eine from-Klausel zu verschachteln ...
Wenn Sie die Unterabfrage unbedingt benötigen, gibt es eine Problemumgehung, die jedoch aus mehreren Gründen hässlich ist, einschließlich der Leistung:
Die verschachtelte Unterabfrage in der FROM-Klausel erstellt eine implizite temporäre Tabelle , sodass sie nicht als dieselbe Tabelle zählt, die Sie aktualisieren.
... aber achten Sie auf den Abfrageoptimierer
Beachten Sie jedoch, dass der Optimierer ab MySQL 5.7.6 möglicherweise die Unterabfrage optimiert und dennoch den Fehler ausgibt. Glücklicherweise kann die
optimizer_switch
Variable verwendet werden, um dieses Verhalten auszuschalten. obwohl ich nicht empfehlen kann, dies als etwas anderes als eine kurzfristige Lösung oder für kleine einmalige Aufgaben zu tun.Vielen Dank an Peter V. Mørch für diesen Rat in den Kommentaren.
Die Beispieltechnik stammt von Baron Schwartz, der ursprünglich bei Nabble veröffentlicht und hier umschrieben und erweitert wurde.
quelle
SET optimizer_switch = 'derived_merge=off';
:-(NexusRex bot eine sehr gute Lösung zum Löschen mit Join aus derselben Tabelle.
Wenn du das tust:
Sie werden eine Fehlermeldung erhalten.
Wenn Sie die Bedingung jedoch noch einmal einpacken, wählen Sie:
es würde das Richtige tun !!
Erläuterung: Das Abfrageoptimierungsprogramm führt eine abgeleitete Zusammenführungsoptimierung für die erste Abfrage durch (wodurch der Fehler fehlschlägt), die zweite Abfrage ist jedoch nicht für die abgeleitete Zusammenführungsoptimierung geeignet . Daher ist der Optimierer gezwungen, zuerst die Unterabfrage auszuführen.
quelle
Das
inner join
in Ihrer Unterabfrage ist nicht erforderlich. Es sieht so aus, als ob Sie die Einträge löschen möchten, instory_category
denen sich dascategory_id
nicht in dercategory
Tabelle befindet.Mach das:
Stattdessen:
quelle
DISTINCT
das hier für unnötig - für eine bessere Leistung;).where in
in der ID-Spalte, damit Sie die Primärtabelle nicht abfragen müssen.Vor kurzem musste ich Datensätze in derselben Tabelle aktualisieren, in der ich es wie folgt gemacht habe:
quelle
UPDATE skills SET type='Development' WHERE type='Programming';
? Dies scheint die ursprüngliche Frage nicht zu beantworten.UPDATE skills SET type='Development' WHERE type='Programming';
. Ich verstehe nicht, warum so viele Leute nicht darüber nachdenken, was sie tun ...quelle
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. In ähnlicher Weise fungiert in der Antwort von @ NexusRex die ersteSELECT
Abfrage als abgeleitete Tabelle, in diestory_category
zum zweiten Mal verwendet wird. Der im OP erwähnte Fehler sollte hier also nicht auftreten, oder?Wenn du nicht kannst
Da es sich um dieselbe Tabelle handelt, können Sie Folgendes tun:
[aktualisieren oder löschen oder was auch immer]
quelle
Dies habe ich getan, um einen Prioritätsspaltenwert um 1 zu aktualisieren, wenn er in einer Tabelle> = 1 ist und in seiner WHERE-Klausel eine Unterabfrage in derselben Tabelle verwendet, um sicherzustellen, dass mindestens eine Zeile Priorität = 1 enthält (da dies der war Bedingung, die während der Aktualisierung überprüft werden muss):
Ich weiß, dass es ein bisschen hässlich ist, aber es funktioniert gut.
quelle
Der einfachste Weg, dies zu tun, besteht darin, einen Tabellenalias zu verwenden, wenn Sie auf eine übergeordnete Abfragetabelle innerhalb der Unterabfrage verweisen.
Beispiel:
Ändern Sie es in:
quelle
Sie können 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 damit gemeint hat, es in zwei Schritten zu tun.
quelle
Laut der von @CheekySoft verknüpften MySQL-UPDATE-Syntax steht ganz unten.
Ich denke, Sie löschen aus store_category, während Sie noch in der Union daraus auswählen.
quelle
Für die spezifische Abfrage, die das OP zu erreichen versucht, besteht der ideale und effizienteste Weg, dies zu tun, darin, überhaupt keine Unterabfrage zu verwenden.
Hier sind die
LEFT JOIN
Versionen der beiden Abfragen des OP:Hinweis:
DELETE s
Beschränkt Löschvorgänge auf diestory_category
Tabelle.Dokumentation
quelle
UPDATE
Anweisungen und verknüpften Unterabfragen funktioniert . So können SieLEFT JOIN ( SELECT ... )
im Gegensatz zu durchführenWHERE IN( SELECT ... )
und die Implementierung für viele Anwendungsfälle nützlich machen.Wenn etwas nicht funktioniert, wenn Sie durch die Vordertür kommen, nehmen Sie die Hintertür:
Es ist schnell. Je größer die Daten, desto besser.
quelle
Versuchen Sie, das Ergebnis der Select-Anweisung in einer separaten Variablen zu speichern, und verwenden Sie diese dann zum Löschen der Abfrage.
quelle
Versuche dies
quelle
Wie wäre es mit dieser Abfrage, hoffe es hilft
quelle
DELETE story_category FROM ...
DieLEFT JOIN category AS cat ON cat.id = story_category.category_id WHERE cat.id IS NULL
story_category.id = cat.id
Sie möchten Zeilen löschen, in
story_category
denen keine vorhanden sindcategory
.Hier ist Ihre ursprüngliche Abfrage, um die zu löschenden Zeilen zu identifizieren:
Die Kombination
NOT IN
mit einer Unterabfrage, dieJOIN
die ursprüngliche Tabelle enthält, scheint unnötig kompliziert zu sein. Dies kann mitnot exists
und einer korrelierten Unterabfrage einfacher ausgedrückt werden:Jetzt ist es einfach, dies in eine
delete
Aussage umzuwandeln:Diese Abfrage würde auf jeder MySQL-Version sowie in den meisten anderen mir bekannten Datenbanken ausgeführt.
Demo zu DB Fiddle :
quelle