我在mysql 8中编写了一个查询,其中在insert上的重复键上,由于一个唯一的索引,它只在一定条件下更新受影响的行。我的条件是,如果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条件为true时,只有started_on被更新,而没有其他具有完全相同条件的列。
因此,我的直觉是,我的更新查询(started_on = IF( DATE(started_on) = DATE('2025-01-01'), started_on, '2025-01-06')的第一行突然更新了列started_on,因此由于值的更改,下面的条件结果为false。我尝试的是将更新started_on的部分放在更新的所有列的末尾,现在它们都被更新了。
我想确定一下,如果我的直觉是正确的,我会找到一个确认,但在网上搜索了一点之后,我什么也没有发现。
编辑:运行通过mysql工作台更新started_on的查询,即使在上面也能工作,但我需要使用xdevapi库在节点中运行它,只有放在底部时才能工作。
发布于 2020-12-18 17:27:38
你的直觉是正确的。
这种行为在13.2.13更新说明中有一个例子:
以下语句中的第二个赋值将col2设置为current (已更新) col1值,而不是原始 col1值。结果是col1和col2具有相同的值。此行为与标准SQL不同。 更新t1集col1 = col1 + 1,col2 = col1; 单表更新赋值通常是从左到右的值,从左到右的。
发布于 2020-12-18 22:25:37
在MySQL5.6和所有版本的MariaDB中,任何对列的引用都将得到该列的原始值。
对于MySQL5.7和MySQL8.0,它更复杂:
在单个表更新中,更新实际上是从左到右进行的,每个列更新都获得列的值,就好像前面的所有更新都已应用过一样。
在多表更新中,似乎对主表的任何更新都是首先发生的,从左到右,就像在单个表更新中一样。但是,在完成主表更新时,对联接表中的列的更新似乎总是得到任何值,因此对主表列的任何更改都将生效,即使这些主表列仅在语句的后面设置,对于连接表列的引用,也使用原始值,即使这些已连接的表列在语句中的前面被更改。
https://stackoverflow.com/questions/65361117
复制相似问题