Mysql多表更新-结果不一致

x33g5p2x  于 2023-02-21  发布在  Mysql
关注(0)|答案(2)|浏览(206)
UPDATE 
  table1 alias1
  ,table2 alias2 
SET  
  alias2.CURRENT_CD_BALANCE = alias2.CURRENT_CD_BALANCE - alias1.ORIGINAL_AMOUNT 
  ,alias1.COMMENT = concat('Sum of ',alias1.ORIGINAL_AMOUNT,' Cancelled')
  ,alias1.BALANCE = 0
  ,alias1.ORIGINAL_AMOUNT = 0
  ,TRAN_TYPE = 'D'  
WHERE 
   alias1.STORE_ID = alias2.STORE_ID 
   AND alias1.ACCTNO = alias2.ACCTNO  
  AND alias1.AR_TRANS_ID = value1;

Query OK, 1 row affected (0.001 sec) Rows matched: 2 Changed: 1 Warnings: 0
在运行上述查询之前
alias1.ORIGINAL_AMOUNT is 900000alias2.CURRENT_CD_BALANCE is the 900000.
运行查询后,tabel1.ORIGINAL_AMOUNT设置为零,但alias2.CURRENT_CD_BALANCE不变(值仍为900000)。
这意味着在执行操作'alias2.CURRENT_CD_BALANCE = alias2.CURRENT_CD_BALANCE - alias1.ORIGINAL_AMOUNT'之前将alias1.ORIGINAL_AMOUNT设置为零。
但是,alias1.COMMMENT列的值为'Sum of 900000 Cancelled',这表明alias1.ORIGINAL_AMOUNT的初始值在被设置为零之前被分配给了alias1.COMMENT。
为什么会这样呢?
应该如何构造此查询,以便在将alias2.CURRENT_CD_BALANCE设置为零之前从alias2.CURRENT_CD_BALANCE中减去alias1.ORIGINAL_AMOUNT的初始值?
服务器的响应表明这两个表是
我试过使用不带别名的连接来重构查询,组合(STORE_ID,ACCTNO)在两个表上都是唯一的键,AR_TRANS_ID也是唯一的。

fquxozlt

fquxozlt1#

多表UPDATE中的赋值顺序是不确定的,SET子句中的赋值表达式以不确定的顺序执行。
如果要确定地执行此操作,则必须使用源表的两个副本。第一个副本用于更新,另一个副本提供更新数据。大多数情况下,更新数据可以在子查询中获取,这比使用两个单独的表更理想。
即,代替非确定性

UPDATE t1
  JOIN t2 ON {join expression}
SET t1.col1 = expression(t2.col1),   -- imagine that there is
    t2.col2 = expression(t1.col2)    -- a cross-assignment there

你会用

UPDATE t1
  JOIN t2 ON {join expression}
  JOIN ( SELECT t1.id id1, t2.id id2,             -- are used for to identify updated rows
                expression(t2.col1) new_t1_col1,  -- the values which will be
                expression(t1.col2) new_t2_col2   -- used for data updating
         FROM t1
         JOIN t2 ON {join expression}
        ) new_data ON t1.id = new_data.id1 AND t2.id = new_data.id2
SET t1.col1 = new_data.t1_col1,
    t2.col2 = new_data.t2_col2;
qyswt5oh

qyswt5oh2#

来自(文件):
单表UPDATE赋值通常从左到右计算。对于多表更新,不能保证赋值按任何特定顺序执行。
我不得不对结构进行一些猜测,但这足以重现你所看到的:

CREATE TABLE table1 (
    ACCTNO INT,
    STORE_ID INT,
    AR_TRANS_ID INT,
    TRAN_TYPE CHAR(1),
    ORIGINAL_AMOUNT DECIMAL(8,2),
    BALANCE DECIMAL(8,2),
    COMMENT VARCHAR(255)
);
INSERT INTO table1 VALUES (1, 1, 1, 'D', 900000, 900000, NULL);

CREATE TABLE table2 (
    ACCTNO INT,
    STORE_ID INT,
    CURRENT_CD_BALANCE DECIMAL(8,2)
);
INSERT INTO table2 VALUES (1, 1, 900000);

通过颠倒连接中表的顺序,我观察到了预期的行为:

UPDATE table2 alias2
JOIN table1 alias1
    ON alias1.STORE_ID = alias2.STORE_ID
    AND alias1.ACCTNO = alias2.ACCTNO
SET
    alias2.CURRENT_CD_BALANCE = alias2.CURRENT_CD_BALANCE - alias1.ORIGINAL_AMOUNT,
    alias1.COMMENT = concat('Sum of ',alias1.ORIGINAL_AMOUNT,' Cancelled'),
    alias1.BALANCE = 0,
    alias1.ORIGINAL_AMOUNT = 0,
    TRAN_TYPE = 'D' 
WHERE alias1.AR_TRANS_ID = value1;

db<>fiddle
考虑到上面引用的MySQL文档,我不确定依赖它是否合适。
我不能100%确定您要达到的目的,但它似乎是某种财务交易的冲销和相关摘要的更新。通常,交易历史记录应视为不可更改,任何更改都必须作为新交易应用,而不是对现有交易的修订。

相关问题