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?
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 clauseWHERE
pour limiter les résultats, aussi.
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
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
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 = ?
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.
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)
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
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;
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);