428

我有一个简单的 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);

我尝试运行以下更新,但只收到错误 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
))

我搜索了错误并从 mysql 以下页面http://dev.mysql.com/doc/refman/5.1/en/subquery-restrictions.html中找到,但这对我没有帮助。

我该怎么做才能更正sql查询?

4

11 回答 11

857

问题是,无论出于何种原因,MySQL 都不允许您编写这样的查询:

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

也就是说,如果您正在对表执行UPDATE// INSERTDELETE则不能在内部查询中引用该表(但是,您可以从该外部表中引用字段......)


解决方案是用 替换myTable子查询中的实例(SELECT * FROM myTable),像这样

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

这显然会导致必要的字段被隐式复制到临时表中,因此是允许的。

我在这里找到了这个解决方案。那篇文章的注释:

您不想只SELECT * FROM table在现实生活中的子查询中;我只是想让示例保持简单。实际上,您应该只在最里面的查询中选择您需要的列,并添加一个好的WHERE子句来限制结果。

于 2013-01-13T10:45:06.070 回答
53

您可以通过三个步骤完成此操作:

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;

或者

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
于 2010-12-13T13:47:21.777 回答
27

在 Mysql 中,不能通过子查询同一张表来更新一张表。

您可以将查询分成两部分,或者执行

将 TABLE_A 更新为 A
 INNER JOIN TABLE_A AS B ON A.field1 = B.field1
 设置字段2 = ?
于 2012-03-09T21:40:12.520 回答
25

从子查询中创建一个临时表 (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
)

我引入了一个单独的名称(别名)并为临时表的“persID”列提供了一个新名称

于 2012-07-18T01:43:52.753 回答
18

这很简单。例如,不要写:

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

你应该写

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

或类似的。

于 2012-09-19T14:58:18.663 回答
16

BlueRaja 发布的方法很慢,我修改了它,因为我用来从表中删除重复项。如果它可以帮助任何拥有大表的人原始查询

DELETE FROM table WHERE id NOT IN (SELECT MIN(id) FROM table GROUP BY field 2)

这需要更多时间:

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

更快的解决方案

DELETE FROM table WHERE ID NOT IN(
   SELECT t.Id FROM (SELECT MIN(Id) AS Id FROM table GROUP BY field2) AS t)
于 2015-06-07T21:01:12.987 回答
11

MySQL 不允许从一个表中选择并同时在同一个表中更新。但总有一种解决方法:)

这不起作用>>>>

UPDATE table1 SET col1 = (SELECT MAX(col1) from table1) WHERE col1 IS NULL;

但这有效>>>>

UPDATE table1 SET col1 = (SELECT MAX(col1) FROM (SELECT * FROM table1) AS table1_new) WHERE col1 IS NULL;
于 2020-06-15T04:44:52.377 回答
9

MariaDB 从 10.3.x 开始取消了这个(对于DELETEUPDATE):

更新 - 具有相同源和目标的语句

从 MariaDB 10.3.2 开始,UPDATE 语句可能具有相同的源和目标。

在 MariaDB 10.3.1 之前,以下 UPDATE 语句将不起作用:

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

从 MariaDB 10.3.2 开始,语句成功执行:

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

DELETE - 相同的源表和目标表

在 MariaDB 10.3.1 之前,无法从具有相同源和目标的表中删除。从 MariaDB 10.3.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 - 成功

于 2018-06-07T19:49:59.907 回答
7

作为参考,您还可以使用 Mysql 变量来保存临时结果,例如:

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

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

于 2017-07-06T08:16:31.587 回答
3

如果您尝试从 tableA 读取 fieldA 并将其保存在同一表的 fieldB 上,当 fieldc = fieldd 时,您可能需要考虑这一点。

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(例如 access )

来源:我自己试过

于 2013-05-08T09:37:44.560 回答
0

其他解决方法包括在子查询中使用 SELECT DISTINCT 或 LIMIT,尽管它们对具体化的影响并不那么明确。这对我有用

如MySql Doc中所述

于 2019-08-26T06:51:00.040 回答