2016-11-15 52 views
2

我想以相当复杂的方式更新一个表,并且决定将内表连接到它自己的表是有用的。 (为了给出一些背景,表格存储通过chain_id字段链接的记录的短链,并且在链中通过日期字段进行排序。更新需要处理具有与日期不同的最近日期的符号。其他人在其链中,也可能需要将一些链分成多个单独的链)。在MySQL中更新一个表内连接本身

这是我所看到的一个简化版本:

CREATE TABLE t(
    `a` INT(3) NOT NULL, 
    `b` INT(3) 
    ); 

INSERT INTO t VALUES (3,4),(3,6); 

SELECT * FROM t; 

------------ 
| a | b | 
------------- 
| 3 | 4 | 
| 3 | 6 | as expected 


UPDATE t t1 
INNER JOIN t t2 
ON (t1.a = t2.a 
AND t1.b > t2.b) 
SET t1.b = t1.a 
AND t2.b = t1.a; 

SELECT * FROM t; 

------------ 
| a | b | 
------------- 
| 3 | 4 | 
| 3 | 0 | wat 

我本来希望得到是:

------------ 
| a | b | 
------------- 
| 3 | 3 | 
| 3 | 3 | 

所以很明显,这是个不错的计划,但让我有三个问题:

1.)这里发生了什么事?

2.)由于无论发生什么事情都不太可能是预期的,MySQL为什么会允许它?

3)是否有另一种方式来实现类似我的本意(即实际更新的表内加入了与自身,不只是把一切都设置为3 ...)

+1

更新与本身的内部连接的表是(在我看来)一个非常糟糕的主意。你很可能有深度未知的层次结构,因此最好的方法是(假设MySQL不支持递归查询)实现一个简单的递归函数,在每个**链**中找到合适的值,并且在递归完全倒回时,更新拨款记录。 – FDavidov

回答

2

@CGritton解释为什么只有1纪录被更新,但没有提供确切的信息,为什么b字段在第二次记录的情况下设置为0。

解决方案的第一条线索是,您得到set子句错误。如果要更新2个字段,则需要用逗号分隔两个分配,而不要使用and运算符。正确的说法应该是:

UPDATE t t1 
INNER JOIN t t2 
ON (t1.a = t2.a 
AND t1.b > t2.b) 
SET t1.b = t1.a, t2.b = t1.a; 

如果我们分析原始set条款:

SET t1.b = t1.a AND t2.b = t1.a 

注意,即赋值运算符具有较低的优先级,那么and运营商,因此上述表达式将被执行如:

SET t1.b = ((t1.a AND t2.b) = t1.a) 

如果我代替数字到位的字段名称:

SET t1.b = ((3 AND 4) = 3) 

(3 AND 4)为0,0 = 3是0,因此t1.b将被设置为0

我不完全理解你想实现你的查询是什么,所以我不能提出一个最终版本给你。但第一个更正版本应该是你的一个很好的起点。只要确保你了解你的加入标准。

1

内的条件只能加入返回一行,所以只有一行正在更新。

> select * 
from t t1 
INNER JOIN t t2 
ON (t1.a = t2.a 
AND t1.b > t2.b) 

+ ------ + ------ + ------ + ------ + 
| a  | b  | a  | b  | 
+ ------ + ------ + ------ + ------ + 
| 3  | 6  | 3  | 4  | 
+ ------ + ------ + ------ + ------ + 

至于为什么0,检查了这一点:

create table two_updates (a int(3)); 

insert into two_updates values (1); 

update two_updates set a = 99 and a = 99; 

select * from two_updates; 

+ ------ + 
| a  | 
+ ------ + 
| 0  | 
+ ------ + 

在您的查询,你问的MySQL两次更新同一领域,即使采用相同的价值,即使它有一个不同的别名。

你可以用这个替换你的更新语句并且靠近,但是行(3,4)不会被更新,因为它不是内部连接的一部分。

UPDATE t t1 
INNER JOIN t t2 
ON (t1.a = t2.a 
AND t1.b > t2.b) 
SET t1.b = t1.a; 

+ ------ + ------ + 
| a  | b  | 
+ ------ + ------ + 
| 3  | 4  | 
| 3  | 3  | 
+ ------ + ------ +