Vous ne pouvez pas spécifier la table cible pour la mise à jour dans la clause FROM

j'ai une table mysql simple:

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

j'ai essayé d'exécuter la mise à jour suivante, mais je n'obtiens que l'erreur 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
))

j'ai cherché l'erreur et j'ai trouvé à partir de mysql la page suivante http://dev.mysql.com/doc/refman/5.1/en/subquery-restrictions.html , mais ça ne m'aide pas.

Que dois-je faire pour corriger la requête sql?

274
demandé sur OMG Ponies 2010-12-13 16:36:50

9 réponses

le problème est que MySQL, pour quelque raison que ce soit, ne vous permet pas d'écrire des requêtes comme ceci:

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

C'est-à-dire, si vous faites UPDATE / INSERT / DELETE sur une table, vous ne pouvez pas référencer cette table dans une requête interne (vous can cependant référence un champ de cette table extérieure...)


la solution est de remplacer la instance de myTable dans la sous-requête avec (SELECT * FROM myTable) , comme ceci

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

Cela fait apparemment que les champs nécessaires sont implicitement copiés dans une table temporaire, donc c'est autorisé.

j'ai trouvé cette solution ici . Une note de cet article:

vous ne voulez pas juste SELECT * FROM table dans le sous-Query dans la vraie vie; je voulais juste garder les exemples simples. Dans en réalité, vous ne devriez sélectionner que les colonnes dont vous avez besoin dans cette requête interne, et ajouter une bonne clause WHERE pour limiter les résultats, aussi.

569
répondu BlueRaja - Danny Pflughoeft 2017-02-16 16:04:01

vous pouvez faire cela en trois étapes:

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;

ou

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
répondu Michael Pakhantsov 2013-08-10 16:14:44

faire une table temporaire (tempP) à partir d'un sous-article

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
)

j'ai introduit un nom séparé (alias) et donner un nouveau nom à la colonne' persID 'pour la table temporaire

20
répondu Budda 2013-03-09 20:42:56

Dans Mysql, vous ne pouvez pas mettre à jour une table par sous-requête de la même table.

vous pouvez séparer la requête en deux parties, ou faire

 UPDATE TABLE_A AS A
 INNER JOIN TABLE_A AS B ON A.field1 = B.field1
 SET field2 = ? 
19
répondu Yuantao 2013-12-31 02:42:20

c'est assez simple. Par exemple, au lieu d'écrire:

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

il faut écrire

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

ou similaire.

14
répondu DarkSide 2015-02-26 15:26:20

L'approche affichée par BlueRaja est lente Je l'ai modifié comme J'utilisais pour supprimer les doubles de la table. Au cas où il aide quelqu'un avec de grandes tables Requête Originale

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

cela prend plus de temps:

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

Solution Plus Rapide

DELETE FROM table where ID NOT IN(
   SELECT x.Id from (SELECT MIN(Id) as Id from table GROUP BY field2) AS t)
12
répondu Ajak6 2015-06-07 21:01:12

si vous essayez de lire fieldA à partir de tableA et de le sauvegarder sur fieldB sur la même table, lorsque fieldc = fieldd vous voudrez peut-être considérer ceci.

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

copie la valeur de fieldA à fieldB lorsque condition-field a rempli votre condition. cela fonctionne aussi dans ADO(E. g accès)

source: essayé moi-même

3
répondu krish KM 2013-05-08 09:37:44

tout comme référence, vous pouvez également utiliser des Variables Mysql pour enregistrer des résultats temporaires, par exemple:

SET @v1 := (SELECT ... );
UPDATE ... SET ... WHERE x=@v1;

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

2
répondu Filippo Mazza 2017-07-06 08:16:31

MariaDB a levé ce à partir de 10.3.x (pour DELETE et UPDATE ):

mettre à JOUR les Énoncés Avec la Même Source et Cible

D'après MariaDB 10.3.2, les déclarations de mise à jour peuvent avoir la même source et la même cible.

Jusqu'à MariaDB 10.3.1, la mise à jour suivante ne fonctionnerait pas:

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

de MariaDB 10.3.2, la déclaration s'exécute avec succès:

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

supprimer-même Table Source et cible

Jusqu'à MariaDB 10.3.1, la suppression d'un tableau avec la même source et la même cible n'était pas possible. De MariaDB 10.3.1, c'est maintenant possible. Par exemple:

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

DBFiddle MariaDB 10.2-Error

DBFiddle MariaDB 10.3-Success

0
répondu Lukasz Szozda 2018-08-23 17:40:22