448 Stimmen

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

Ich habe eine einfache mysql-Tabelle:

CREATE TABLE IF NOT EXISTS `pers` (
  `persID` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(35) NOT NULL,
  `gehalt` int(11) NOT NULL,
  `chefID` int(11) DEFAULT NULL,
  PRIMARY KEY (`persID`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

INSERT INTO `pers` (`persID`, `name`, `gehalt`, `chefID`) VALUES
(1, 'blb', 1000, 3),
(2, 'as', 1000, 3),
(3, 'chef', 1040, NULL);

Ich habe versucht, das folgende Update auszuführen, aber ich erhalte nur die Fehlermeldung 1093:

UPDATE pers P 
SET P.gehalt = P.gehalt * 1.05 
WHERE (P.chefID IS NOT NULL 
OR gehalt < 
(SELECT (
    SELECT MAX(gehalt * 1.05) 
    FROM pers MA 
    WHERE MA.chefID = MA.chefID) 
    AS _pers
))

Ich suchte nach dem Fehler und fand von mysql folgende Seite http://dev.mysql.com/doc/refman/5.1/en/subquery-restrictions.html aber das hilft mir nicht weiter.

Was soll ich tun, um die SQL-Abfrage zu korrigieren?

895voto

Das Problem ist, dass MySQL, aus welchem Grund auch immer, es nicht erlaubt, solche Abfragen zu schreiben:

UPDATE myTable
SET myTable.A =
(
    SELECT B
    FROM myTable
    INNER JOIN ...
)

Das heißt, wenn Sie eine UPDATE / INSERT / DELETE auf eine Tabelle, können Sie diese Tabelle nicht in einer inneren Abfrage referenzieren (Sie kann jedoch ein Feld aus dieser äußeren Tabelle referenzieren...)


Die Lösung besteht darin, die Instanz von myTable in der Unterabfrage mit (SELECT * FROM myTable) wie diese

UPDATE myTable
SET myTable.A =
(
    SELECT B
    FROM (SELECT * FROM myTable) AS something
    INNER JOIN ...
)

Dies führt offenbar dazu, dass die erforderlichen Felder implizit in eine temporäre Tabelle kopiert werden, was also zulässig ist.

Ich habe diese Lösung gefunden aquí . Eine Anmerkung zu diesem Artikel:

Sie wollen nicht nur SELECT * FROM table in der Unterabfrage im wirklichen Leben; ich wollte die Beispiele nur einfach halten. In Wirklichkeit sollten Sie nur die Spalten auswählen, die Sie in dieser innersten Abfrage benötigen, und eine gute WHERE Klausel, um auch die Ergebnisse einzuschränken.

53voto

Michael Pakhantsov Punkte 24167

Sie können es in drei Schritten herstellen:

CREATE TABLE test2 AS
SELECT PersId 
FROM pers p
WHERE (
  chefID IS NOT NULL 
  OR gehalt < (
    SELECT MAX (
      gehalt * 1.05
    )
    FROM pers MA
    WHERE MA.chefID = p.chefID
  )
)

...

UPDATE pers P
SET P.gehalt = P.gehalt * 1.05
WHERE PersId
IN (
  SELECT PersId
  FROM test2
)
DROP TABLE test2;

oder

UPDATE Pers P, (
  SELECT PersId
  FROM pers p
  WHERE (
   chefID IS NOT NULL 
   OR gehalt < (
     SELECT MAX (
       gehalt * 1.05
     )
     FROM pers MA
     WHERE MA.chefID = p.chefID
   )
 )
) t
SET P.gehalt = P.gehalt * 1.05
WHERE p.PersId = t.PersId

29voto

Budda Punkte 17532

Erstellen einer temporären Tabelle (tempP) aus einer Unterabfrage

UPDATE pers P 
SET P.gehalt = P.gehalt * 1.05 
WHERE P.persID IN (
    SELECT tempP.tempId
    FROM (
        SELECT persID as tempId
        FROM pers P
        WHERE
            P.chefID IS NOT NULL OR gehalt < 
                (SELECT (
                    SELECT MAX(gehalt * 1.05) 
                    FROM pers MA 
                    WHERE MA.chefID = MA.chefID) 
                    AS _pers
                )
    ) AS tempP
)

Ich habe einen separaten Namen (Alias) eingeführt und der Spalte "persID" für die temporäre Tabelle einen neuen Namen gegeben

28voto

Yuantao Punkte 2714

In Mysql können Sie eine Tabelle nicht durch eine Unterabfrage derselben Tabelle aktualisieren.

Sie können die Abfrage in zwei Teile trennen, oder

 UPDATE TABLE\_A AS A
 INNER JOIN TABLE\_A AS B ON A.field1 = B.field1
 SET field2 = ?

19voto

DarkSide Punkte 3530

Es ist ganz einfach. Zum Beispiel, statt zu schreiben:

INSERT INTO x (id, parent_id, code) VALUES (
    NULL,
    (SELECT id FROM x WHERE code='AAA'),
    'BBB'
);

sollten Sie schreiben

INSERT INTO x (id, parent_id, code)
VALUES (
    NULL,
    (SELECT t.id FROM (SELECT id, code FROM x) t WHERE t.code='AAA'),
    'BBB'
);

oder ähnlich.

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