为行级值引用另一个 table - 在 IF 条件下执行 INSERT INTO ... ON DUPLICATE KEY UPDATE

Reference another table for row-level values - in IF condition when doing INSERT INTO ... ON DUPLICATE KEY UPDATE

我有订单和采购。 采购有很多订单。

我正在尝试使用 ON DUPLICATE KEY UPDATE 当订单行重复时 仅当 来自购买的连接行 table 具有特定列一定的价值。

INSERT INTO `orderlines` 
    (col1, col2) 
    VALUES 
    ('val1', 'val2') 
ON DUPLICATE KEY UPDATE 
    col3 = IF (purchases.status_id=0, 'truevalue' , col3);

所以这个查询只处理 orderlines table。但我想从 purchases table 中引用 purchases.status_id

我不知道如何使 purchases table 中的字段在此查询中可用。

这个问题可以有一个解决方案,但是它需要我假设您的程序知道 values 提供给 INSERT 查询的内容,因此,它们是被用作变量。这只是为了确保 UDPATE 中需要的子查询可以根据需要进行控制。因此,例如 INSERT INTO orderlines (col1, col2) VALUES ('val1', 'val2') ....。也就是说,在这种情况下,这两个变量/值在程序中都是可用的。


我们从 orderlines table 开始(出于本次尝试的目的,id 在此处被视为 PRIMARY KEY):

id  |  col1      |  col2      |  col3
----------------------------------------------
1   |  1 - col1  |  1 - col2  |  1 - col3
2   |  2 - col1  |  2 - col2  |  2 - col3
3   |  3 - col1  |  3 - col2  |  3 - col3
4   |  4 - col1  |  4 - col2  |  4 - col3

并定义purchasestable如下(同id就是这里table这里的FOREIGN KEY):

id  |  status_id 
-----------------
1   |  0  
2   |  1

从而表明 id = 1 col3 应在 orderlines table 中更新为 truevalue,以防 INSERT操作遇到 DUPLICATE KEY 记录。


因此查询如下:

INSERT INTO orderlines (id, col1, col2)
    VALUES (1, "1 - col1 - updated", "1 - col2 - updated")
    ON DUPLICATE KEY
    UPDATE 
        col3 = IF(
                     (SELECT CASE 
                                WHEN purchases.status_id = 0 THEN "truevalue" 
                             ELSE "falsevalue" 
                      END AS title 
                      FROM purchases WHERE id = 1
                     ) = "truevalue", 
                     "truevalue", 
                     col3
                 );

(也请在查询的 INSERTSELECT 部分尝试 运行 与 id = 2 进行相同的查询。


如您所见,SELECT 查询要求 WHERE 子句中的 相同 id INSERT 查询 — 潜在的 DUPLICATE KEY 候选人。此查询会将 orderlines 中的 col3 更新为 id = 1 中的 truevalue(因为其对应的 status_idpurchases 中的 0 table),但如果相同的查询是 运行 for id = 2,则 col3 将保持不变。最终输出将是:

id  |  col1      |  col2      |  col3
----------------------------------------------
1   |  1 - col1  |  1 - col2  |  truevalue      ---> updated
2   |  2 - col1  |  2 - col2  |  2 - col3       ---> unchanged
3   |  3 - col1  |  3 - col2  |  3 - col3
4   |  4 - col1  |  4 - col2  |  4 - col3

Demo link


此外,如果程序中使用了此查询,那么您还可以控制 status_id 字段的指定值。

不,您不能像您在假设解决方案中显示的那样直接在表达式中引用另一个 table。

Dhruv Saxena 的解决方案之所以有效,是因为它使用了子查询。

但是使用 INSERT...SELECT 应该更容易:

INSERT INTO `orderlines` 
    (order_id, col1, col2, col3) 
SELECT id, 'val1', 'val2', IF(status_id=0, 'truevalue', NULL)
FROM purchases
WHERE order_id=1
ON DUPLICATE KEY UPDATE
  col3 = COALESCE(VALUES(col3), col3);

仅当购买的请求行具有条件 status_id=0 时,才会为 col3 分配 'truevalue' 字符串。如果不是,则它保持 col3 不变,因为 select-列表中的 NULL 使 COALESCE() return 成为第二个参数。

我不确定我的列是否适合您的 table 关系,但此解决方案应该展示了该技术。

诀窍是对执行所需连接的重复键更新执行子查询。以下查询所做的假设是 order_id 对订单行和采购都是通用的,并且 col1 具有唯一键。

INSERT INTO `orderlines` 
    (col1, col2) 
    VALUES 
    ('val1', 'val2') 
ON DUPLICATE KEY UPDATE 
    col3 = (select IF(p.status_id=0, 'truevalue' , o.col3)
            from orderlines o
            join purchases p on p.order_id=o.order_id  -- assuming this is the proper join expression between orderlines and purchases
            and o.col1='val1');                        -- and col1 has the unique key