You can't specify target table for update in FROM clause
我有一个简单的mysql表:
1 2 3 4 5 6 7 8 9 10 11 12 | 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); |
我试图运行以下更新,但我只得到错误1093:
1 2 3 4 5 6 7 8 9 10 | 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 )) |
我搜索了错误,并在http://dev.mysql.com/doc/refman/5.1/en/subquery-restrictions.html页面的mysql中找到,但它对我没有帮助。
我该怎么做才能纠正sql查询?
问题在于,无论出于什么原因,MySQL都不允许你编写这样的查询:
1 2 3 4 5 6 7 | UPDATE myTable SET myTable.A = ( SELECT B FROM myTable INNER JOIN ... ) |
也就是说,如果您在表上执行
解决方案是用
1 2 3 4 5 6 7 | UPDATE myTable SET myTable.A = ( SELECT B FROM (SELECT * FROM myTable) AS something INNER JOIN ... ) |
这显然会导致必要的字段被隐式复制到临时表中,所以它是允许的。
我在这里找到了解决方案。该文的说明:
You don’t want to just
SELECT * FROM table in the subquery in real life; I just wanted to keep the examples simple. In reality, you should only be selecting the columns you need in that innermost query, and adding a goodWHERE clause to limit the results, too.
您可以分三步完成:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 ) ) |
...
1 2 3 4 5 6 7 8 | UPDATE pers P SET P.gehalt=P.gehalt * 1.05 WHERE PersId IN ( SELECT PersId FROM test2 ) DROP TABLE test2; |
要么
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
在Mysql中,您不能通过子查询同一个表来更新一个表。
您可以将查询分为两部分,或者执行
1 2 3 | UPDATE TABLE_A AS A INNER JOIN TABLE_A AS B ON A.field1 = B.field1 SET field2 = ? |
从子查询创建临时表(tempP)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 ) |
我已经引入了一个单独的名称(别名),并为临时表的'persID'列提供了一个新名称
这很简单。例如,而不是写:
1 2 3 4 5 | INSERT INTO x (id, parent_id, code) VALUES ( NULL, (SELECT id FROM x WHERE code='AAA'), 'BBB' ); |
你应该写
1 2 3 4 5 6 | INSERT INTO x (id, parent_id, code) VALUES ( NULL, (SELECT t.id FROM (SELECT id, code FROM x) t WHERE t.code='AAA'), 'BBB' ); |
或类似的。
BlueRaja发布的方法很慢我将其修改为
我用来删除表中的重复项。万一它可以帮助任何人拥有大桌子
原始查询
1 | DELETE FROM TABLE WHERE id NOT IN (SELECT MIN(id) FROM TABLE GROUP BY FIELD 2) |
这需要更多时间:
1 2 | DELETE FROM TABLE WHERE ID NOT IN( SELECT MIN(t.Id) FROM (SELECT Id,field2 FROM TABLE) AS t GROUP BY field2) |
更快的解决方案
1 2 | DELETE FROM TABLE WHERE ID NOT IN( SELECT x.Id FROM (SELECT MIN(Id) AS Id FROM TABLE GROUP BY field2) AS t) |
作为参考,您也可以使用Mysql变量来保存临时结果,例如:
1 2 | SET @v1 := (SELECT ... ); UPDATE ... SET ... WHERE x=@v1; |
https://dev.mysql.com/doc/refman/5.7/en/user-variables.html
如果您尝试从tableA读取fieldA并将其保存在同一个表的fieldB上,则当fieldc = fieldd时,您可能需要考虑这一点。
1 2 3 4 5 6 7 | UPDATE tableA, tableA AS tableA_1 SET tableA.fieldB= tableA_1.filedA WHERE (((tableA.conditionFild) = 'condition') AND ((tableA.fieldc) = tableA_1.fieldd)); |
当条件字段满足您的条件时,上面的代码将fieldA中的值复制到fieldB。这也适用于ADO(例如访问)
来源:试过自己
MariaDB从10.3.x(
UPDATE - Statements With the Same Source and Target
From MariaDB 10.3.2, UPDATE statements may have the same source and target.
Until MariaDB 10.3.1, the following UPDATE statement would not work:
1
2
3 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 DATAFrom MariaDB 10.3.2, the statement executes successfully:
1 UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);
DELETE - Same Source and Target Table
Until MariaDB 10.3.1, deleting from a table with the same source and target was not possible. From MariaDB 10.3.1, this is now possible. For example:
1 DELETE FROM t1 WHERE c1 IN (SELECT b.c1 FROM t1 b WHERE b.c2=0);
DBFiddle MariaDB 10.2 - 错误
DBFiddle MariaDB 10.3 - 成功
update x set available_material_id = null其中id不在(从x中选择id,其中additional_info = 1);
1 2 3 4 5 6 | -- use left join ---- UPDATE x LEFT JOIN x xx ON x.id = xx.id AND xx.additional_info = 1 SET available_material_id = NULL WHERE xx.id IS NULL; |