【问题标题】:How do I remove ON UPDATE CURRENT_TIMESTAMP from an existing column?如何从现有列中删除 ON UPDATE CURRENT_TIMESTAMP?
【发布时间】:2015-10-28 15:27:52
【问题描述】:

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

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

我正在搜索ALTER TABLE 语句,该语句将删除 ON UPDATE CURRENT_TIMESTAMP 规则而不进行任何其他更改。在我的想象中,它应该类似于ON UPDATE NOOPON UPDATE NO_CURRENT_TIMESTAMP

ON UPDATE JUST_BE_A_NORMAL_COLUMN?

我尝试在 mysql 工作台中使用“清除默认值”选项,但它做了与应该做的相反的事情 - 它给了列一个默认值!

我能够使用 ALTER TABLE t ALTER COLUMN c DROP DEFAULT 摆脱默认值,因此该列在 INSERT 中是强制性的(就像在转储/重新加载之前一样,正如我所希望的那样),但在 UPDATE 上不需要的行为仍然存在。

我没有启用explicit_defaults_for_timestamp 选项。如果我从头开始,我肯定会使用该选项,因为它看起来更加理智。但由于我已经按照我在 5.5 中希望的方式配置了列,因此我希望它们在转移到 5.6 时保持相同的语义。显然 mysqldump 不够聪明。

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

更新:

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

如果没有explicit_defaults_for_timestamp,两步过程肯定不会在5.6 服务器上产生正确的结果;这表明 5.6 没有完美地模仿这种模式下的旧行为,或者旧服务器从来没有做我认为它正在做的事情。我不确定是哪个。

【问题讨论】:

    标签: mysql timestamp


    【解决方案1】:
    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;
    

    【讨论】:

    • 我需要一种方法来做到这一点而不添加一个默认值。您的建议会创建一个默认值,然后如果我放弃默认值,自动更新属性就会恢复。
    • 见第二条alter语句。这会修改列而不指定默认值。
    • 这带来了所有“隐藏的默认”行为 - CURRENT_TIMESTAMP 作为插入和自动更新的默认值。也许使用 explicit_defaults_for_timestamp 它会起作用。但是由于我发现如果不重新启动服务器就无法设置该选项,因此我无法立即进行测试。
    • 实际上,在第二次尝试时,您的第一个建议和ALTER TABLE ... ALTER COLUMN ... DROP DEFAULT 似乎正在起作用。我仍在试图弄清楚为什么这种确切的组合有效而其他类似的组合无效。
    • 这仍然没有意义,但我已经收集了足够的信息来描述(如果没有解释)行为。作为一个幸运的副作用,我也解决了我原来的问题。我将我的结果发布为自我回答,但我感谢您为我指明了正确的方向。
    【解决方案2】:

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

    • mysql 5.5.45
    • mysql 5.6.26 没有explicit_defaults_for_timestamp
    • 带有explicit_defaults_for_timestamp 的mysql 5.6.26

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

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

    这个状态不能用一个 CREATE TABLE 命令重新创建,它不能在 mysqldump 中存活。

    没有explicit_defaults_for_timestamp 的5.6 是最有趣的情况。和 5.5 差不多,但是DROP DEFAULT 命令不一样。如果您尝试“使用默认值 0 创建然后删除默认值”序列,神奇的更新属性会作为删除的副作用出现。但是,如果您使用默认的 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;
    

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

    【讨论】:

    • 接受您的回答! (我很荣幸在 10k 用户中遇到同样的问题:D)
    • 也可以在 5.7 上工作!谢谢!!
    【解决方案3】:

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

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

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

    请参阅此问题以获得对差异的良好解释: Should I use field 'datetime' or 'timestamp'?

    【讨论】:

      【解决方案4】:

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

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

      如果我理解 documentation 正确启用 explicit_defaults_for_timestamp 是必须能够定义声明为 NOT NULL 且没有显式 DEFAULTTIMESTAMP 列。

      【讨论】:

      • 我怀疑你是对的。我希望文档能更清楚地说明该选项对现有列的影响,这样我就可以更有信心打开它。冒险一试……set @@explicit_defaults_for_timestamp=1 没用。只读变量。我想这意味着它需要重新启动服务器。
      【解决方案5】:

      如果您想同时删除 DEFAULT 值和 ON UPDATE 值,除了以下内容对我有帮助

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

      【讨论】:

        猜你喜欢
        • 2016-05-30
        • 2011-09-29
        • 2017-04-26
        • 2012-01-01
        • 2011-07-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多