使用JOIN进行UPDATE应用于所有记录

时间:2017-10-23 09:04:25

标签: mysql

我有3张桌子:

TABLE bon                       TABLE order         TABLE payed 
b_id | total | payed | diff     id | b_id | amm     id | b_id | amm 
-----+-------+-------+------    ---+------+-----    ---+------+-----
  1  |   0   |   0   |  0        1 |   1  |   5      1 |   2  | -10
-----+-------+-------+------    ---+------+-----    ---+------+-----
  2  |   0   |   0   |  0        2 |   2  |   5      2 |   3  |  -5  
-----+-------+-------+------    ---+------+-----    ---+------+-----
  3  |   0   |   0   |  0        3 |   1  |  15
                                ---+------+-----
                                 4 |   3  |  10
                                ---+------+-----
                                 5 |   2  |  15
                                ---+------+-----
                                 6 |   2  |  20

如果我想仅为一个ID更新 bon 中的总计,我会这样做:

UPDATE `bon`
    INNER JOIN (
        SELECT
        SUM(`amm`) AS `total`
        FROM `order` 
        WHERE `b_id`=2
    ) AS s1

    INNER JOIN (
        SELECT
        COALESCE(SUM(`amm`),0) AS `payed`
        FROM `payed` 
        WHERE `b_id`=2
    ) AS s2

    SET
    `bon`.`total` = s1.`total`,
    `bon`.`payed` = s2.`payed`,
    `bon`.`diff` = s1.`total` + s2.`payed`
WHERE `b_id`=2;

id 2 正确更新为

b_id | total | payed | diff   
-----+-------+-------+------
  2  |   40  |  -10  |  30

但是,我尝试使用以下内容更新所有 ID

UPDATE `bon`
    INNER JOIN (
        SELECT
        `b_id`,
        SUM(`amm`) AS `total`
        FROM `order` 
    ) AS s1 ON bon.`b_id`=s1.`b_id`

    INNER JOIN (
        SELECT
        `b_id`,
        SUM(`amm`) AS `payed`
        FROM `payed` 
    ) AS s2 ON bon.`b_id`=s2.`b_id`

    SET
    `bon`.`total` = s1.`total`,
    `bon`.`payed` = COALESCE(s2.`payed`,0),
    `bon`.`diff` = s1.`total` + COALESCE(s2.`payed`,0)

可悲的是,这不会更新任何行。那我在哪里错了?

Here's a fiddle

编辑:我找到了解决方案并将其发布在下方。不知道这是否是最好的方法,但它有效(建议仍然欢迎)。

2 个答案:

答案 0 :(得分:1)

虽然我还没有找到解决方案,但我认为您的第二个查询存在一些问题。

1)让我们看看你的第一个内部查询:

SELECT
`b_id`,
SUM(`amm`) AS `total`
FROM `order` 

首先,这将从order中提取所有行,但是您将其别名为total的计算列将在每个中包含相同的值行

这可能不是你想要的。将SELECT的结果集与bon表连接起来 not 意味着MySQL会在幕后使用一些魔法,并在列中使用的结果组中使用JOIN

相反,首先构建表bon中的叉积和第一个SELECT的结果集(此叉积也具有{em>相同的值{每行{1}}。 total只会过滤JOINbin.b_id相同的行。

当然,这些行中的每一行仍然具有相同的s1.b_id值,因此即使进行了更新,也会得到错误的结果。

补救措施是在total语句中添加b_id分组。这将导致SELECT被正确计算,即每total。然后,您可以使用分组 b_id作为b_id

这同样适用于您的第二个JOIN内部查询。

2)您正在使用表格SELECT中的INNER JOIN进行SELECT。这意味着结果将不包含任何不在payed中的行。使用示例数据,结果将不包含payedb_id的行(因为您的1表不包含此类行。)

这个问题并不容易解决。一种解决方案是在运行查询之前确保payed表中的每个b_id。但是,如果payed表中不存在的ID未更新,您可能会感到高兴。

如果您更详细地描述您想要的内容,我们最终可以找到解决方案。

答案 1 :(得分:0)

我找到了一个解决方案,跳过了所有的JOINS。也许不是最好的答案,但它有效(建议仍然欢迎):

UPDATE `bon`
    SET
    `bon`.`total` = 
        (SELECT 
            COALESCE(SUM(`amm`),0)
            FROM `order`
            WHERE `order`.`b_id`=`bon`.`b_id`
            ),
    `bon`.`payed` = 
        (SELECT 
            COALESCE(SUM(`amm`),0)
            FROM `payed`
            WHERE `payed`.`b_id`=`bon`.`b_id`
            ),
    `bon`.`diff` = 
            (SELECT 
            COALESCE(SUM(`amm`),0)
            FROM `order` 
            WHERE `order`.`b_id`=`bon`.`b_id`
            )+
            (SELECT 
            COALESCE(SUM(`amm`),0)
            FROM `payed`
            WHERE `payed`.`b_id`=`bon`.`b_id`
            )