web-dev-qa-db-de.com

In der FROM-Klausel können Sie keine Zieltabelle für die Aktualisierung 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, nach dem Update auszuführen, bekomme aber 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 habe nach dem Fehler gesucht und in mysql folgende Seite http://dev.mysql.com/doc/refman/5.1/de/subquery-restrictions.html gefunden, aber es hilft mir nicht.

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

301
CSchulz

Das Problem ist, dass MySQL es Ihnen aus irgendeinem Grund nicht erlaubt, Abfragen wie die folgenden zu schreiben:

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

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


Die Lösung besteht darin, die Instanz von myTable in der Unterabfrage durch (SELECT * FROM myTable) zu ersetzen

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

Dies führt anscheinend dazu, dass die erforderlichen Felder implizit in eine temporäre Tabelle kopiert werden, sodass dies zulässig ist.

Ich habe diese Lösung gefunden hier . Ein Hinweis aus diesem Artikel:

Sie möchten nicht nur SELECT * FROM table in der Unterabfrage im wirklichen Leben eingeben. Ich wollte nur die Beispiele einfach halten. In Wirklichkeit sollten Sie nur die Spalten auswählen, die Sie in dieser innersten Abfrage benötigen, und eine gute WHERE -Klausel hinzufügen, um auch die Ergebnisse einzuschränken.

Sie können dies in drei Schritten machen:

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
52

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

Sie können die Abfrage in zwei Teile teilen oder tun

 UPDATE TABLE_A AS A 
 INNER JOIN TABLE_A AS B ON A.field1 = B.field1 
 SET Feld2 =? 
21
Yuantao

Erstellen Sie aus einer Unterabfrage eine temporäre Tabelle (TempP)

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 'persID' Spalte für temporäre Tabelle einen neuen Namen gegeben

20
Budda

Es ist ganz einfach. Zum Beispiel anstatt zu schreiben:

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

du solltest 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 ähnliches.

16
DarkSide

Der von BlueRaja gepostete Ansatz ist langsam. Ich änderte ihn als Ich verwendete, um Duplikate aus der Tabelle zu löschen. Falls es jemandem mit großen Tabellen hilft.... Original Query

delete from table where id not in (select min(id) from table group by field 2)

Dies dauert mehr Zeit:

DELETE FROM table where ID NOT IN(
  SELECT MIN(t.Id) from (select Id,field2 from table) AS t GROUP BY field2)

Schnellere Lösung

DELETE FROM table where ID NOT IN(
   SELECT x.Id from (SELECT MIN(Id) as Id from table GROUP BY field2) AS t)
12
Ajak6

Als Referenz können Sie auch Mysql-Variablen verwenden, um temporäre Ergebnisse zu speichern, z.

SET @v1 := (SELECT ... );
UPDATE ... SET ... WHERE [email protected];

https://dev.mysql.com/doc/refman/5.7/de/user-variables.html

3
Filippo Mazza

Wenn Sie versuchen, fieldA aus tableA zu lesen und in fieldB in derselben Tabelle zu speichern, sollten Sie, wenn fieldc = fieldd ist, dies in Betracht ziehen.

UPDATE tableA,
    tableA AS tableA_1 
SET 
    tableA.fieldB= tableA_1.filedA
WHERE
    (((tableA.conditionFild) = 'condition')
        AND ((tableA.fieldc) = tableA_1.fieldd));

Der obige Code kopiert den Wert von Feld A in Feld B, wenn das Bedingungsfeld Ihre Bedingung erfüllt. das funktioniert auch in ADO (z. B. Zugriff)

quelle: habe mich selbst versucht

3
krish KM

MariaDB hat dies ab 10.3.x (beide für DELETE und UPDATE) aufgehoben:

UPDATE - Anweisungen mit derselben Quelle und demselben Ziel

UPDATE-Anweisungen haben in MariaDB 10.3.2 möglicherweise dieselbe Quelle und dasselbe Ziel.

Bis MariaDB 10.3.1 würde die folgende UPDATE-Anweisung nicht funktionieren:

UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);
  ERROR 1093 (HY000): Table 't1' is specified twice, 
  both as a target for 'UPDATE' and as a separate source for data

In MariaDB 10.3.2 wird die Anweisung erfolgreich ausgeführt:

UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);

DELETE - Gleiche Quell- und Zieltabelle

Das Löschen aus einer Tabelle mit derselben Quelle und demselben Ziel war bis MariaDB 10.3.1 nicht möglich. Ab MariaDB 10.3.1 ist dies jetzt möglich. Zum Beispiel:

DELETE FROM t1 WHERE c1 IN (SELECT b.c1 FROM t1 b WHERE b.c2=0);

DBFiddle MariaDB 10.2 - Fehler

DBFiddle MariaDB 10.3 - Erfolg

0
Lukasz Szozda

Andere Problemumgehungen umfassen die Verwendung von SELECT DISTINCT oder LIMIT in der Unterabfrage, obwohl diese in ihrer Auswirkung auf die Materialisierung nicht so explizit sind. das hat bei mir funktioniert

wie in MySql Doc erwähnt

0
PITU