【问题标题】:timestamp autoupdate not working with ON DUPLICATE KEY UPDATE (PDO)时间戳自动更新不适用于 ON DUPLICATE KEY UPDATE (PDO)
【发布时间】:2014-06-09 21:01:00
【问题描述】:

我有一个将时间戳设置为自动更新的表格作品集。

CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

PHP 中的 PDO 语句不会导致时间戳更新。

$statement = $this->connection->prepare("
INSERT INTO folio(publication, productId) 
VALUES(:publication, :productId) 
ON DUPLICATE KEY UPDATE 
id=LAST_INSERT_ID(id), publication=:publication, productId=:productId");

遵循手动方法可行,但不可取。

$statement = $this->connection->prepare(
"INSERT INTO folio(publication, productId) 
VALUES(:publication, :productId) 
ON DUPLICATE KEY UPDATE 
id=LAST_INSERT_ID(id), publication=:publication, productId=:productId, timestamp=NOW()");

更新:这是我的作品集表结构

CREATE TABLE `folio` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `publication` varchar(255) DEFAULT NULL,
  `productId` varchar(255) DEFAULT NULL,
  `timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_folio` (`publication`,`productId`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

更新 2:将时间戳设置为非空后的表结构

CREATE TABLE `folio` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `publication` varchar(255) DEFAULT NULL,
  `productId` varchar(255) DEFAULT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_folio` (`publication`,`productId`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

【问题讨论】:

  • 请张贴folio 表结构。此外,您的查询有问题 - 无需更新 on duplicate key 部分中的所有字段,只需更新 publicationproductId。而且 - 将您的字段命名为 timestamp 是一个非常糟糕的主意,因为它是保留字。
  • @AndyW 用表格结构更新问题
  • @AndyW 也没有让您了解“无需更新重复键中的所有字段”也许您在代码中的回答会为我解决这个问题
  • publication 和 productID 的值是否与重复行中的对应列不同?在此处阅读用户评论下的第二条评论:dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html“如果没有任何变化,这将不起作用,可能是因为 MySQL 根本不运行虚拟更新”。
  • @bloodyKnuckles 似乎是这样,我只检查了发布和 productId,它们是执行语句中唯一要更新/插入的字段,这意味着它属于虚拟更新,因此作为一种解决方法,我将在查询中使用 timestamp=NOW(),请发表评论

标签: php mysql timestamp on-duplicate-key


【解决方案1】:

据我所知,您查询的问题可能是因为您将 timestamp 字段设为可空

`timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

尝试将其设为 NOT NULL - 因为您有有效的默认值,MySQL 不会抱怨您没有在查询中提供值:

`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

另外,尝试将 timestamp 字段重命名为更合理的名称,例如:

`changed_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

另外,正如我的 cmets 中所述 - 您无需在 ON DUPLICATE KEY 部分提供所有字段,而只需提供数据字段:

INSERT INTO folio(publication, productId) 
VALUES(:publication, :productId) 
ON DUPLICATE KEY UPDATE 
    publication=:publication, 
    productId=:productId

这是因为如果 MySQL 检测到您有重复的 key 条件,它不会插入新行,而是更新现有行,因此 id 列必须保持不变。

更新

似乎不更新 timestamp 列是记录在案的行为 - MySQL manual for TIMESTAMP columns

引用需要的段落:

如果列是自动更新的,那么当行中任何其他列的值从其当前值更改时,它会自动更新为当前时间戳。如果所有其他列都设置为其当前值,则该列保持不变。为了防止该列在其他列更改时更新,请将其显式设置为其当前值。要在其他列未更改的情况下更新该列,请将其显式设置为应具有的值(例如,将其设置为 CURRENT_TIMESTAMP)。

因此,您满足所有条件 :) - 当您插入记录时,应正确填充时间戳。 但是当您提供重复值以更新timestamp 时,MySQL 会看到您设置了行中已经存在的值(否则它不会重复),因此它不会更新timestamp 列。

因此,解决方案很简单,您已经找到了 - 每当您提供重复值时,明确更新 timestamp 列,例如:

INSERT INTO folio(publication, productId) 
VALUES(:publication, :productId) 
ON DUPLICATE KEY UPDATE 
    `timestamp` = NOW()

无论如何,使timestamp NOT NULL 不会受到伤害。

【讨论】:

  • 恐怕设置不为空以及重命名字段都不起作用,而且您提供所有字段的观点仍然不清楚(您的查询与我的相似,我只是更新出版物和 productId p.s. 都是复合唯一键)
  • 我也为mysql保留字时间戳使用了反引号来摆脱它,它工作正常
  • 您尝试设置为NOT NULL 还是只是猜测?我有一个包含大约 100 个表的系统,其中大多数都使用可自动更新的时间戳列 - 一切都像一个魅力。显然,所有这些列都是NOT NULL,因此这是我在您的代码中注意到的第一件事。
  • 在 Not Null 之后更新了表结构,我是否也应该将发布和 productId 设为 NN?
  • 这完全取决于您对数据模型的要求 - 将某些字段设置为 NULL 意味着您声明“此字段有时可以采用未知值,我可以接受”。可自动更新的时间戳字段有点不同,因为 MySQL 会“神奇地”对待它,所以像可空性这样的一些选项可能会破坏魔法。
【解决方案2】:

如果新的 INSERT 值与重复行中的旧值相同,则显然 MySQL 不会执行 UPDATE,因此不会触发 ON UPDATE CURRENT_TIMESTAMP。 :(

因此,作为一种笨拙的解决方法,您可以向表中添加一个虚拟字段,从而强制执行 UPDATE(在重复 id 的情况下):

$statement = $this->connection->prepare("
    INSERT INTO folio(publication, productId) 
      VALUES(:publication, :productId) 
      ON DUPLICATE KEY UPDATE 
      id=LAST_INSERT_ID(id), publication=:publication, productId=:productId,
      dummy = NOT dummy
");

...正如用户评论中所建议的那样:http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

【讨论】:

  • 它只会添加一个不必要的定义层,但是,当您发现正在发生虚拟更新时,您会得到答案......
  • 酷。我更新了我的回复,以便人们更容易找到该评论。
【解决方案3】:

只是

在创建重复键更新时插入 your_table (a, b) 值 (?, ?) = current_timestamp

无论好坏,MySQL 在任何情况下都不会在插入唯一类型调用的情况下默认更新时间戳。

  • 您使用的是 insert-on-dupe、replace、insert-ignore 这三个中的哪一个并不重要

  • 无论您在字段、表格或其他任何内容上使用哪些设置或质量,它都没有任何区别

只需在末尾添加created = current_timestamp 即可手动完成。

不幸的是,就是这样!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-23
    • 1970-01-01
    • 2012-07-08
    相关资源
    最近更新 更多