mysql UPDATE 语句逐一更新列?

mysql UPDATE statement updates columns one by one?

我在 mysql 8 中编写了一个查询,其中由于唯一索引,在插入的重复键上,它仅在特定条件下更新受影响的行。我的条件是 started_on 列值是否已更改。所以我写了这个查询

INSERT INTO timers (
            started_on,
            end_on,
            message,
            first_alert_before_end_time,
            alerts_interval,
            referred_flow_instance_id,
            referred_page_id,
            referred_json_timer_id,
            started_by_user_id
        ) VALUES (
            '2025-01-06',
            DATE_ADD('2025-01-06', INTERVAL 5184000 SECOND),
            'Sta scadendo il fascicolo',
            2592000,
            86400,
            1413,
            14,
            1,
            79
        )
        ON DUPLICATE KEY 
        UPDATE
            started_on = IF( DATE(started_on) = DATE('2025-01-01'), started_on, '2025-01-06'),
            end_on = IF( DATE(started_on) = DATE('2025-01-01'), end_on,  DATE_ADD('2025-01-06', INTERVAL 5184000 SECOND)),
            started_by_user_id = IF( DATE(started_on) = DATE('2025-01-01'), started_by_user_id, 79),
            deleted_by_user_id = IF( DATE(started_on) = DATE('2025-01-01'), deleted_by_user_id, NULL),
            reminded_later_by_user_id = IF( DATE(started_on) = DATE('2025-01-01'), reminded_later_by_user_id, NULL),
            deleted = IF( DATE(started_on) = DATE('2025-01-01'), deleted, 0)
    ;

我不会分析有效的插入,只会分析重复键部分的更新。

我注意到一个意想不到的结果:当更新中的 IF 条件为真时,只有 started_on 被更新,但没有其他具有完全相同条件的列。

所以我的直觉是更新查询的第一行 (started_on = IF( DATE(started_on) = DATE('2025-01-01'), started_on, '2025-01-06') 突然更新了列 started_on,因此以下条件结果为假,因为值已更改。 我尝试的是将更新 started_on 的部分放在更新中所有列的末尾,现在它们都得到了更新。

如果我的直觉是正确的,我想确定并找到确认,但在网上搜索了一下后我什么也没找到。

编辑:似乎运行通过mysql更新started_on的查询workbench即使在顶部也能正常工作,但我需要运行 它在使用 xdevapi 库的节点中,只有放在底部才能工作。

你的直觉是正确的。
13.2.13 UPDATE Statement 中记录了此行为,并附有示例:

The second assignment in the following statement sets col2 to the current (updated) col1 value, not the original col1 value. The result is that col1 and col2 have the same value. This behavior differs from standard SQL.

UPDATE t1 SET col1 = col1 + 1, col2 = col1;

Single-table UPDATE assignments are generally evaluated from left to right.

在 mysql 5.6 和 MariaDB 的所有版本中,对列的任何引用都将获得该列的原始值。

对于mysql5.7和mysql8.0,比较复杂:

在单个 table 更新中,更新实际上是从左到右发生的,每个列更新都获取列的值,就好像所有之前的更新都已应用一样。

在多 table 更新中,似乎对主要 table 的任何更新首先发生,从左到右,就像在单 table 更新中一样。但是更新连接 tables 中的列似乎总是在主 table 更新完成时获得任何值,因此对主 table 列的任何更改都将生效,即使那些主 table 列仅在语句的后面设置,对于连接的 table 列的引用,使用原始值,即使那些连接的 table 列在语句的前面被更改.

fiddle