如何从现有列中删除 ON UPDATE CURRENT_TIMESTAMP?

How do I remove ON UPDATE CURRENT_TIMESTAMP from an existing column?

我转储了 mysql 5.5 数据库并将其加载到 5.6 服务器中。

转储添加了 ON UPDATE CURRENT_TIMESTAMP 到一堆以前没有的列。

我正在搜索一个 ALTER TABLE 语句,它将删除 ON UPDATE CURRENT_TIMESTAMP 规则而不进行任何其他更改。在我的想象中应该是 ON UPDATE NOOP 或者 ON UPDATE NO_CURRENT_TIMESTAMP.

ON UPDATE JUST_BE_A_NORMAL_COLUMN?

我尝试在 mysql workbench 中使用 "Clear default" 选项,但它做了与它应该做的相反的事情 - 它给了列一个默认值!

我能够使用 ALTER TABLE t ALTER COLUMN c DROP DEFAULT 摆脱默认值,因此该列在 INSERTs 中是强制性的(就像我想要的 dump/reload 之前一样)但是不需要的行为关于更新仍然存在。

我没有启用 explicit_defaults_for_timestamp 选项。如果我是新手,我肯定会使用该选项,因为它看起来更理智。但是因为我已经在 5.5 中按照我想要的方式配置了列,所以我希望它们在转移到 5.6 时保持相同的语义。显然 mysql转储不够聪明。

在这一点上,我不确定我是否理解启用 explicit_defaults_for_timestamp 会产生什么影响。该选项会改变现有 table 的行为,还是只会改变未来 CREATE TABLE 命令的解释?打开它会以某种方式帮助我修复损坏的列吗?

更新:

一个类似的问题是 here,但那个问题是关于创建一个新的 table,而不是改变现有的列。事实上,这个问题是我在 5.5 服务器上创建 table 时用作指南的问题。我使用了两步程序:使用默认值 0 创建以抑制更新 CURRENT_TIMESTAMP,然后删除默认值。

如果没有 explicit_defaults_for_timestamp,两步程序肯定不会在 5.6 服务器上产生正确的结果;这是一个迹象,表明 5.6 没有完美地模仿这种模式下的旧行为,或者旧服务器从未按照我的想法去做。我不确定是哪个。

ALTER TABLE mytable
     CHANGE mycolumn
            mycolumn TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP

相信这将重置并使ON UPDATE无效。这将有效地使这个定义:

CREATE TABLE mytable (
  # Other Columns
  mycolumn timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
)

换成这个:

CREATE TABLE mytable (
  # Other Columns
  mycolumn timestamp NOT NULL default CURRENT_TIMESTAMP
)

如果您想完全重置该列,您应该能够像这样简单地重新定义它:

ALTER TABLE mytable
     CHANGE mycolumn
            mycolumn TIMESTAMP NOT NULL;

尝试启用 explicit_defaults_for_timestamp 系统变量,然后重新定义列:

ALTER TABLE `table` CHANGE COLUMN `col` `col` TIMESTAMP NOT NULL;

如果我理解 documentation 正确启用 explicit_defaults_for_timestamp 是强制性的,以便能够定义声明为 NOT NULLTIMESTAMP 列并且没有明确的 DEFAULT .

使用其他答案的想法,以及几个新安装的 mysql 服务器实例,我对 3 种不同服务器配置上的几个不同 CREATE 和 ALTER 命令的行为进行了比较:

  • mysql 5.5.45
  • mysql 5.6.26 无 explicit_defaults_for_timestamp
  • mysql 5.6.26 与 explicit_defaults_for_timestamp

最容易解释的是 5.6 和 explicit_defaults_for_timestamp。一切都很正常。 timestamp 类型与任何其他类型没有明显不同。在打开 explicit_defaults_for_timestamp 标志之前创建的列保留其旧的默认值和魔术更新。

在 5.5 中,隐式默认值在创建时间戳列时发生(如果它是 table 中的第一个时间戳列)。这些已经有据可查。可以通过设置显式默认值来避免魔术更新行为,然后可以删除默认值,为列保留 3 个所需属性:不可为空、无默认值、无魔术更新。这是 CREATE TABLE t (TIMESTAMP c NOT NULL DEFAULT 0)ALTER TABLE t ALTER COLUMN c DROP DEFAULT 的结果。

无法使用单个 CREATE TABLE 命令重新创建此状态,并且它不会在 mysql 转储后继续存在。

5.6 没有 explicit_defaults_for_timestamp 是最有趣的情况。和5.5差不多,只是DROP DEFAULT命令不一样。如果您尝试 "create with default 0 then drop default" 序列,魔法更新属性会作为掉落的副作用出现。但是,如果您使用默认值 CURRENT_TIMESTAMP 而不是 0,则 DROP DEFAULT 可以正常工作而不会产生副作用。 (一定是一个错误。我无法想象它会故意这样做的任何原因。)

因此,这对命令在我测试的所有服务器配置上都会产生相同的结果:

ALTER TABLE t CHANGE COLUMN c c TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE t ALTER COLUMN c DROP DEFAULT;

该列现在没有默认值,也没有魔术更新。

对于您的用例,我认为使用 DATETIME 会更好,例如:

ALTER TABLE `my_table`
    CHANGE `my_col` `my_col` DATETIME NOT NULL DEFAULT NOW();

这将在插入时默认为 NOW(),但在更新时不受影响。

查看这个问题以获得对差异的很好解释: Should I use field 'datetime' or 'timestamp'?

如果你想删除默认值和更新值,只有以下帮助我

ALTER TABLE `your_table` CHANGE `your_column` `your_column` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00';