在MySQL

时间:2016-11-15 14:47:47

标签: mysql

我试图以一种相当复杂的方式更新表,并决定将表连接到自身是有用的。

(为了给出一些背景知识,该表存储通过chain_id字段链接的短链记录,并在链中按日期字段排序。更新需要处理最近日期与其他日期不同的符号在它的链中,也可能需要将一些链分成多个独立的链)。

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

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 ......)

2 个答案:

答案 0 :(得分:2)

@CGritton解释了为什么只更新了1条记录,但没有提供关于为什么b字段在第2条记录中被设置为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 :(得分: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      |
+ ------ + ------ +