我有一个简单的 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查询?
问题是,无论出于何种原因,MySQL 都不允许您编写这样的查询:
UPDATE myTable
SET myTable.A =
(
SELECT B
FROM myTable
INNER JOIN ...
)
也就是说,如果您在表上执行 UPDATE
/INSERT
/DELETE
,则不能在内部查询中引用该表(但您可以引用该外部表中的字段...)
解决方法是将子查询中的myTable
实例替换为(SELECT * FROM myTable)
,像这样
UPDATE myTable
SET myTable.A =
(
SELECT B
FROM (SELECT * FROM myTable) AS something
INNER JOIN ...
)
这显然会导致必要的字段被隐式复制到临时表中,因此是允许的。
我找到了这个解决方案 here。那篇文章的注释:
您不想在现实生活中只在子查询中使用 SELECT * FROM 表;我只是想让示例保持简单。实际上,您应该只在最里面的查询中选择您需要的列,并添加一个好的 WHERE 子句来限制结果。
您可以通过三个步骤完成此操作:
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
CREATE TABLE
语句重写为多个步骤 - 我希望作者意识到这一点。然而,这是唯一的解决方案吗?或者可以用子查询或连接重写查询吗?为什么(不)这样做?
UPDATE Pers P
不应该改为 UPDATE pers P
吗?
CREATE TABLE AS SELECT
的表现不是很糟糕吗?
在 Mysql 中,不能通过子查询同一张表来更新一张表。
您可以将查询分成两部分,或者执行
UPDATE TABLE_A AS A INNER JOIN TABLE_A AS B ON A.field1 = B.field1 SET field2 = ?
SELECT ... SET
?我从来没有听说过这个。
TABLE_A
时使用 AS B
。最受支持的示例中的答案可以使用 AS T
来简化,而不是使用可能效率低下的 FROM (SELECT * FROM myTable) AS something
,幸运的是,查询优化器通常会消除但可能并不总是这样做。
从子查询中创建一个临时表 (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”列提供了一个新名称
SELECT ( SELECT MAX(gehalt * 1.05)..
- 第一个 SELECT
不选择任何列。
这很简单。例如,不要写:
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'
);
或类似的。
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)
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;
作为参考,您还可以使用 Mysql 变量来保存临时结果,例如:
SET @v1 := (SELECT ... );
UPDATE ... SET ... WHERE x=@v1;
https://dev.mysql.com/doc/refman/5.7/en/user-variables.html
ERROR 1242 (21000): Subquery returns more than 1 row
MariaDB 从 10.3.x 开始取消了这一点(对于 DELETE
和 UPDATE
):
UPDATE - 具有相同源和目标的语句 从 MariaDB 10.3.2 开始,UPDATE 语句可能具有相同的源和目标。在 MariaDB 10.3.1 之前,以下 UPDATE 语句将不起作用: UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);错误 1093 (HY000):表 't1' 被指定两次,既作为 'UPDATE' 的目标,又作为数据的单独源 从 MariaDB 10.3.2,语句成功执行:UPDATE t1 SET c1=c1+1 WHERE c2 =(从 t1 中选择 MAX(c2));
删除 - 相同的源和目标表 在 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.3 - Success
如果您尝试从 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 )
来源:我自己试过
T
和(SELECT * FROM T)
是完全等价的。它们是相同的关系。因此,这是一个任意的、毫无意义的限制。更具体地说,这是一种强制 MySQL 做它显然可以做的事情的解决方法,但由于某种原因,它不能以更简单的形式解析。DELETE FROM t WHERE tableID NOT IN (SELECT viewID FROM t_view);
我还建议在之后运行OPTIMIZE TABLE t;
以减小表的大小。