MySQL Error 1093 - Können nicht festlegen, Ziel-Tabelle für die Aktualisierung in der FROM-Klausel

StackOverflow https://stackoverflow.com/questions/45494

Frage

Ich habe eine Tabelle story_category in meiner Datenbank mit korrupten Einträgen.Die nächste Abfrage gibt das beschädigte Einträge:

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, ausfü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 - können Sie nicht angeben, target table 'story_category' for update in FROM-Klausel

Wie kann ich das umgehen?

War es hilfreich?

Lösung

Update:Diese Antwort deckt die Allgemeine Fehler-Klassifizierung.Für eine genauere Antwort auf die Frage, wie Sie am besten behandeln Sie die OP die genaue Abfrage, bitte siehe andere Antworten auf diese Frage

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

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

Wenn die Logik ist einfach genug, um re-Form der Abfrage, verlieren Sie die Unterabfrage, und schließt sich dem Tisch zu sich, geeignete Kriterien bei der Auswahl.Dadurch werden MySQL finden Sie in der Tabelle als zwei verschiedene Dinge, so dass destruktiven Veränderungen voran zu gehen.

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

Alternativ versuchen Verschachtelung der Unterabfrage, um tiefer in die from-Klausel ...

Wenn du unbedingt die Unterabfrage gibt es eine Problemumgehung, aber es ist hässliche aus mehreren Gründen, einschließlich der Leistung:

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

Die verschachtelte Unterabfrage in der FROM-Klausel erstellt eine implizite temporäre Tabelle, also es zählt nicht, wie die gleiche Tabelle, die Sie aktualisieren.

...aber aufpassen, für den query-Optimizer

Jedoch, beachten Sie, dass aus MySQL 5.7.6 und weiter, der Optimierer kann die Optimierung aus der Unterabfrage, und immer noch geben Sie den Fehler.Zum Glück, die optimizer_switch Variablen können verwendet werden, um schalten Sie dieses Verhalten;zwar konnte ich nicht empfehlen, dies zu tun, als etwas mehr als eine Kurzfristige Verlegenheit, oder für die kleine one-off tasks.

SET optimizer_switch = 'derived_merge=off';

Dank Peter V.Mørch für diese Beratung in die Kommentare.

Beispiel-Technik wurde von Baron Schwartz, ursprünglich erschienen bei Nabble, umformuliert und erweitert hier.

Andere Tipps

NexusRex sofern eine sehr gute Lösung für das löschen mit der Verknüpfung aus der gleichen 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
)

Sie erhalten eine Fehlermeldung.

Aber wenn Sie wickeln den Zustand in einem mehr wählen:

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
)

es würde das richtige tun!!

Erklärung: Der Abfrageoptimierer eine abgeleitet merge-Optimierung für die erste Abfrage (die bewirkt, dass es zu fehl mit dem Fehler), aber die zweite Abfrage nicht qualifiziert für die abgeleitet merge-Optimierung.Damit der Optimierer gezwungen ist, zum ausführen der ersten Unterabfrage.

Die inner join in Ihrem sub-Abfrage ist nicht notwendig.Es sieht aus wie Sie möchten, löschen Sie die Einträge in story_category wo die category_id nicht in der category Tabelle.

Tun Sie dies:

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

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);

Kürzlich hatte ich zum aktualisieren von Datensätzen in derselben Tabelle ich habe es wie unten:

UPDATE skills AS s, (SELECT id  FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development' 
WHERE s.id = p.id;
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
)

Wenn Sie nicht tun können

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

denn es ist die gleiche Tabelle haben, können Sie betrügen und zu tun :

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

[update-oder delete-oder was auch immer]

Dies ist, was ich Tat, für die Aktualisierung eine Spalte "Priorität" den Wert um 1, wenn es >=1 in einer Tabelle und in der WHERE-Klausel mit einer Unterabfrage auf derselben Tabelle zu machen sicher, dass mindestens eine Zeile enthält Priority=1 (denn das war die Bedingung überprüft werden, während der Durchführung der update) :


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 hat funktioniert.

Sie könnte geben Sie die gewünschte Zeilen-ids in eine temporäre Tabelle und löschen Sie alle Zeilen in dieser Tabelle.

was kann das sein, was @Cheekysoft bedeutete, indem Sie es in zwei Schritten.

Nach die Mysql UPDATE-Syntax verbunden durch @CheekySoft, es sagt rechts unten.

Derzeit, Sie können nicht aktualisieren einer Tabelle, und wählen Sie aus derselben Tabelle in einer Unterabfrage.

Ich denke, Sie werden dem löschen von store_category, während Sie noch auswählen, von der es in der union.

Wenn etwas nicht funktioniert, kommen Sie durch die vordere Tür, dann nehmen Sie die zurück-Tür:

drop table if exists apples;
create table if not exists apples(variety char(10) primary key, price int);

insert into apples values('fuji', 5), ('gala', 6);

drop table if exists apples_new;
create table if not exists apples_new like apples;
insert into apples_new select * from apples;

update apples_new
    set price = (select price from apples where variety = 'gala')
    where variety = 'fuji';
rename table apples to apples_orig;
rename table apples_new to apples;
drop table apples_orig;

Es ist schnell.Je größer die Daten, desto besser.

Der einfachste Weg, dies zu tun ist, verwenden Sie eine alias-Tabelle wenn Sie beziehen sich auf übergeordnete Abfrage Tabelle in der sub-query.

Beispiel :

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

Ändern Sie es:

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

versuchen Sie, diese

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

Versuchen, zu retten das Ergebnis der Select-Anweisung in separaten Variablen und verwenden Sie dann für die Abfrage löschen.

wie wäre es mit dieser Abfrage hoffe es hilft

DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top