使用一对多连接更新语句 [英] Update statements with a one-to-many join

查看:31
本文介绍了使用一对多连接更新语句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我遇到了一个完全不符合我预期的奇怪情况.

So I've come across an odd situation that doesn't behave at all how I expected.

假设我有以下表格:

DROP TABLE IF EXISTS test;
CREATE TABLE test (somekey char(1) PRIMARY KEY, value1 int, value2 int);

INSERT INTO test VALUES 
("a", 1, 1),
("b", 2, 2),
("c", 3, 3);

DROP TABLE IF EXISTS test2;
CREATE TABLE test2 (somekey char(1), thing int, value int);

INSERT INTO test2 VALUES 
("a", 100, 10),
("a", 200, 10),
("b", 100, 20),
("b", 200, 20),
("c", 100, 30),
("c", 200, 30);

现在我想根据 test2 更新 test:

And now I want to update test based on test2:

UPDATE 
    test AS t 
    JOIN test2 AS t2 
        ON t.somekey = t2.somekey
SET
    t.value1 = IF(t2.thing = 100, t2.value, t.value1),
    t.value2 = IF(t2.thing = 200, t2.value, t.value2);

这是我的输出:

SELECT * FROM test;
+---------+--------+--------+
| somekey | value1 | value2 |
+---------+--------+--------+
| a       |     10 |      1 |
| b       |     20 |      2 |
| c       |     30 |      3 |
+---------+--------+--------+

由于某种原因,value2 没有更新.

For some reason, value2 isn't updated.

我发现如果我改变 test2 以便在 100 之前插入 200,则会发生完全相反的情况.这让我相信 MySQL 本质上是按 somekey 分组的,并且完全忽略了 test2 中的一半行.但是,如果我执行完全相同的连接并仅根据 test 更新 test2 中的某些内容,则它不会进行分组和 test2 中的所有六行代码>已更新.

I've found that if I alter test2 such that 200 is inserted before 100, the exact opposite happens. This leads me to believe that MySQL is essentially grouping by somekey, and completely ignoring half the rows in test2. But if I do the exact same join and just update something in test2 based on test, it doesn't do the grouping and all six rows in test2 are updated.

简单的解决方案是简单地连接到 test2 两次,如下所示:

The simple solution is to simple join to test2 twice, like so:

UPDATE 
    test AS t 
    JOIN test2 AS t100 
        ON t100.somekey = t.somekey
        AND t100.thing = 100
    JOIN test2 AS t200
        ON t200.somekey = t.somekey
        AND t200.thing = 200
SET
    t.value1 = t100.value,
    t.value2 = t200.value;

但我只是觉得我不应该这样做.第一次更新有什么问题?为什么 MySQL 会这样?

but I just don't feel I should have to do it this way. What's wrong with the first update? Why is MySQL behaving this way?

推荐答案

使用 JOIN 更新时,如果没有过滤器 (WHERE),则会出现笛卡尔积.在这种情况下,由于每行 test 有 2 行 test2,这意味着每行 test 将有两次更新.

When updating with a JOIN, without a filter (WHERE), there will be a cartesian product. In this case, since there are 2 rows of test2 per single row of test, it means that there will be two updates per test row.

来自文档:

每个匹配的行都会更新一次,即使它多次匹配条件.对于多表语法,不能使用 ORDER BY 和 LIMIT.

Each matching row is updated once, even if it matches the conditions multiple times. For multiple-table syntax, ORDER BY and LIMIT cannot be used.

据我所知,这意味着我们无法控制更新期间将使用 2 个可能的行值中的哪一个 - MySql 选择了 value = value 选项.

Which as far as I can see means that we have no control over which of the 2 possible row values will be used during the update - MySql has chosen the value = value option.

您的第二个更新查询仅为 test.value1test.value2 定义了一个可能的值,从而消除了歧义.

Your second update query defines only a single possible value for test.value1 and test.value2, thus removing the ambiguity.

这篇关于使用一对多连接更新语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆