Я писал запрос в 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 в обновлениях было истинным, обновлялось только start_on, но не другие столбцы с таким же условием.
Итак, моя интуиция заключалась в том, что первая строка моего запроса на обновление (started_on = IF( DATE(started_on) = DATE('2025-01-01'), started_on, '2025-01-06'
) внезапно обновляет столбец start_on, так что следующие условия становятся ложными, потому что значение изменилось.
Я попытался поместить часть, с которой началось обновление, в конец всех столбцов в обновлении, и теперь все они обновляются.
Я хотел бы быть уверенным и найти подтверждение, что моя интуиция была верна, но после небольшого поиска в Интернете я ничего не нашел.
Обновлено: кажется, что запуск запроса, который обновляет start_on сверху через mysql workbench, работает, даже если он сверху, но мне нужно было запустить его в узле с помощью библиотеки xdevapi, и он работает, только если помещен внизу.
Ваша интуиция верна.
Это поведение задокументировано в заявлении 13.2.13 UPDATE с примером:
Второе присваивание в следующем операторе задает для col2 значение текущее (обновленное) значение col1, а не исходное значение col1. Результат заключается в том, что col1 и col2 имеют одинаковое значение. Это поведение отличается от стандартный SQL.
UPDATE t1 SET col1 = col1 + 1, col2 = col1;
Присваивания UPDATE для одной таблицы обычно оцениваются слева направо. верно.
В mysql 5.6 и во всех версиях MariaDB любая ссылка на столбец получит исходное значение этого столбца.
Для mysql 5.7 и mysql 8.0 это сложнее:
При обновлении одной таблицы обновления фактически происходят слева направо, при этом каждое обновление столбца получает значения для столбцов, как если бы были применены все предыдущие обновления.
При обновлении нескольких таблиц кажется, что любые обновления основной таблицы происходят сначала, слева направо, как и при обновлении одной таблицы. Но обновления столбцов в соединенных таблицах, по-видимому, всегда получают какие-либо значения на момент завершения обновления основной таблицы, поэтому любые изменения в столбцах первичной таблицы будут действовать, даже если эти столбцы первичной таблицы будут установлены только позже в операторе, и для ссылок на столбцы объединенной таблицы используется исходное значение, даже если эти столбцы объединенной таблицы были изменены ранее в операторе.