问题描述: 表和数据是这样的

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;

本质是把一个表引用了两次来“迷惑”数据库。