J'ai une simple table mysql:
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 trouvé dans la page suivante de mysql http://dev.mysql.com/doc/refman/5.1/en/subquery-restrictions.html , mais cela ne m'aide pas.
Que dois-je faire pour corriger la requête SQL?
Le problème est que MySQL, pour une raison quelconque, ne vous permet pas d'écrire des requêtes comme celle-ci:
UPDATE myTable
SET myTable.A =
(
SELECT B
FROM myTable
INNER JOIN ...
)
Autrement dit, si vous créez une variable UPDATE
INSERT
/DELETE
sur une table, vous ne pouvez pas référencer cette table dans une requête interne (vous _/can pouvez toutefois référencer un champ à partir de cette table externe ... )
La solution consiste à remplacer l'instance de myTable
dans la sous-requête par (SELECT * FROM myTable)
, comme ceci
UPDATE myTable
SET myTable.A =
(
SELECT B
FROM (SELECT * FROM myTable) AS something
INNER JOIN ...
)
Cela entraîne apparemment la copie implicite des champs nécessaires dans une table temporaire, donc c'est autorisé.
J'ai trouvé cette solution ici . Une note de cet article:
Vous ne voulez pas que
SELECT * FROM table
dans la sous-requête dans la vie réelle; Je voulais juste garder les exemples simples. En réalité, vous ne devez sélectionner que les colonnes dont vous avez besoin dans la requête la plus profonde et ajouter une bonne clauseWHERE
pour limiter également les résultats.
Vous pouvez le faire 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
Dans Mysql, vous ne pouvez pas mettre à jour une table en sous-interrogeant la même table.
Vous pouvez séparer la requête en deux parties ou faire
UPDATE TABLE_A AS A JOINDRE INTERNE TABLE_A AS B ON A.field1 = B.field1 SET champ2 =?
Créer une table temporaire (tempP) à partir d'une sous-requête
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 distinct (alias) et attribué un nouveau nom à la colonne 'persID' pour la table temporaire
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'
);
tu devrais é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 publiée par BlueRaja est lente, je l’ai modifiée en tant que .__ Je l’utilisais pour supprimer les doublons du tableau Au cas où cela aiderait n'importe qui 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)
À titre de référence, vous pouvez également utiliser les variables Mysql pour enregistrer des résultats temporaires, par exemple:
SET @v1 := (SELECT ... );
UPDATE ... SET ... WHERE x=@v1;
Si vous essayez de lire fieldA à partir de tableA et de l'enregistrer sur fieldB dans la même table, vous voudrez peut-être en tenir compte lorsque fieldc = fieldd.
UPDATE tableA,
tableA AS tableA_1
SET
tableA.fieldB= tableA_1.filedA
WHERE
(((tableA.conditionFild) = 'condition')
AND ((tableA.fieldc) = tableA_1.fieldd));
Le code ci-dessus copie la valeur de fieldA à fieldB lorsque condition-field remplissait votre condition. cela fonctionne aussi dans ADO (par exemple, accès)
source: essayé moi-même
MariaDB a levé ce point à partir de 10.3.x (pour DELETE
et UPDATE
)
UPDATE - Instructions de même source et cible
A partir de MariaDB 10.3.2, les instructions UPDATE peuvent avoir la même source et la même cible.
Jusqu'à MariaDB 10.3.1, l'instruction UPDATE 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
A partir de MariaDB 10.3.2, l'instruction s'exécute correctement:
UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);
DELETE - Même source et table cible
Jusqu'à MariaDB 10.3.1, la suppression d'une table avec les mêmes source et cible était impossible. À partir de MariaDB 10.3.1, cela est maintenant possible. Par exemple:
DELETE FROM t1 WHERE c1 IN (SELECT b.c1 FROM t1 b WHERE b.c2=0);
L'utilisation de SELECT DISTINCT ou LIMIT dans la sous-requête est une autre solution de contournement, bien que leur effet sur la matérialisation ne soit pas aussi explicite. cela a fonctionné pour moi