【问题标题】:MySQL SELECT query works but an UPDATE query with same WHERE clause does notMySQL SELECT 查询有效,但具有相同 WHERE 子句的 UPDATE 查询无效
【发布时间】:2021-12-12 14:13:05
【问题描述】:

当在 UPDATE 查询中排除行时,为什么数据库引擎会首先尝试设置错误的日期时间并停止执行?

CREATE TABLE `test`(
  `name` VARCHAR(255) NOT NULL,
  `order_date` DATETIME NULL
)

INSERT INTO `test` (`name`, `order_date`) VALUES
("test nodate", NULL),
("test 2021-10-27", NULL);

-- Both rows are selected with a formatted date taken from the `name`
SELECT *, DATE_FORMAT(RIGHT(`name`, 10), "%Y-%m-%d") AS `date part from name` FROM `test`;

-- The first row with an invalid date in the name is correctly excluded
SELECT *, DATE_FORMAT(RIGHT(`name`, 10), "%Y-%m-%d") AS `date part from name` FROM `test`
WHERE DATE_FORMAT(RIGHT(`name`, 10), "%Y-%m-%d") IS NOT NULL;

-- Error: invalid datetime "est nodate", but that row should be excluded
UPDATE `test` SET
`order_date` = DATE_FORMAT(RIGHT(`name`, 10), "%Y-%m-%d")
WHERE DATE_FORMAT(RIGHT(`name`, 10), "%Y-%m-%d") IS NOT NULL;

DB 小提琴: https://www.db-fiddle.com/f/iUmjxZz3u5bpZesfiD4pzY/1

例如,当尝试使用此更新查询设置无效的日期时间时,引擎不会抛出相同的错误,而我希望它与上面的错误更新语句相同:

UPDATE `test`
SET `order_date` = "invalid"
WHERE `name` <> `name`;

本次更新成功,未更新任何行,但我尝试强制无效日期时间错误。

像 DATE_FORMAT() 这样的函数是执行顺序的特殊情况还是什么? 是否有可能使 UPDATE 查询成功执行?

【问题讨论】:

  • 表是否有id自增?
  • @ErgestBasha 我数据库中的真实表有,小提琴中的表没有。

标签: mysql sql sql-update


【解决方案1】:

在 WHERE 中检测到错误,而不是在 SET 中。

UPDATE `test`
SET `order_date` = NOW()
WHERE DATE_FORMAT(RIGHT(`name`, 10), "%Y-%m-%d") IS NOT NULL;

产生同样的错误。

并且错误发生是由 SQL Server 模式定义的。

Strict SQL Mode

严格模式控制 MySQL 如何处理数据更改语句(如 INSERT 或 UPDATE)中的无效或缺失值。

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=e0bcb8862b10fb8af16b8e2ffb1ae46c

【讨论】:

  • 很好地重现了错误!为什么具有相同 DATE_FORMAT 条件的 SELECT 不会出错?以及如何获得一个有效的 UPDATE 查询来更新来自工作 SELECT 的行?
  • @Piemol 调查整个小提琴,而不是它的一部分。您必须禁用严格模式才能执行更新。 为什么具有相同 DATE_FORMAT 条件的 SELECT 不会出错? 因为 SELECT 不会更改数据。 严格模式控制 MySQL 如何处理数据更改语句(如 INSERT 或 UPDATE)中的无效或缺失值。
【解决方案2】:

操作:

DATE_FORMAT('foo bar baz', '%Y-%m-%d')

导致以下警告

1292-Incorrect datetime value: '...'

现在,根据SQL mode警告将被视为数据更改语句中的错误。这解释了为什么您的 SELECT 语句有效(带有警告)但 INSERT 无效(警告被视为错误)。

Full demo on db<>fiddle

【讨论】:

  • 我现在阅读了 mysql 文档的那一部分。 SELECT 从不抛出警告?当在UPDATE IGNORE 语句中更改它同时保留SQL_MODE STRICT_TRANS_TABLES 时,UPDATE 不会引发错误或警告。我现在得到了帮助,但不理解这种行为的全部 100% :) 编辑: 小提琴没有抛出这些错误,但在我的本地数据库中它是 (Y)
  • 总之,日期函数总是会抛出警告,如果有的话。您可以在执行查询后通过执行SHOW WARNINGS 来查看它们。在严格模式下,警告被视为错误。但是,是的,UPDATE IGNORE 比更改 SQL 模式更好。
猜你喜欢
  • 2018-09-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-19
  • 2012-10-28
  • 1970-01-01
  • 1970-01-01
  • 2017-12-10
  • 1970-01-01
相关资源
最近更新 更多