update 子查询:根据一条数据 update 另一条数据的字段
问题描述: 表和数据是这样的
CREATE TABLE `your_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`A` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`B` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
INSERT INTO `your_table` VALUES (1, 'a1', 'b1');
INSERT INTO `your_table` VALUES (2, 'a2', 'b2');
表名是 your_table ,现在要把 id=1 这条数据的字段 A 和 B 对应值为 a1 b1 改成 id=2 这条数据对应字段的值,也就是 a2 和 b2
跟着直觉走的版本(错误示范)
UPDATE `your_table `
SET
`A` = ( SELECT `A` FROM `your_table` WHERE `id` = 2 ),
`B` = ( SELECT `B` FROM `your_table` WHERE `id` = 2 )
WHERE
`id` = 1;
然后数据库就报错了 1093 - You can't specify target table 'your_table' for update in FROM clause
问了一下 AI (百度)
这个错误提示是MySQL数据库的限制导致的。在MySQL中,你不能在一个子查询中同时从一个表中读取并更新相同的表。这种限制是为了避免可能的竞争条件和不可预期的行为。
为了解决这个问题,你可以使用临时表或者别名的方式绕过这个限制。下面是两种常见的解决方案:
解决方案1:使用临时表 (我没验证,我用的方法二)
你可以首先将需要更新的数据查询出来,存放到一个临时表中,然后再从临时表中更新目标表。
将需要更新的数据查询出来并存放到临时表中:
CREATE TEMPORARY TABLE temp_table AS
SELECT * FROM your_table WHERE id = 2;
从临时表中更新目标表:
UPDATE your_table
SET A = temp_table.A,
B = temp_table.B
FROM temp_table
WHERE your_table.id = 1;
感觉好麻烦 还得清理临时表
解决方案2:使用别名 简单粗暴 (大表慎用,性能很差)
UPDATE your_table t1
JOIN your_table t2 ON t1.id = 1 AND t2.id = 2
SET t1.A = t2.A,
t1.B = t2.B;
本质是把一个表引用了两次来“迷惑”数据库。