【问题标题】:Why there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT clause?为什么在 DEFAULT 子句中只能有一个带有 CURRENT_TIMESTAMP 的 TIMESTAMP 列?
【发布时间】:2010-12-20 12:19:44
【问题描述】:

为什么在 DEFAULT 或 ON UPDATE 子句中只能有一个带有 CURRENT_TIMESTAMP 的 TIMESTAMP 列?

CREATE TABLE `foo` (
  `ProductID` INT(10) UNSIGNED NOT NULL,
  `AddedDate` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `UpdatedDate` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=INNODB;

导致的错误:

错误代码:1293

表定义不正确;可以 只有一个 TIMESTAMP 列 CURRENT_TIMESTAMP 为 DEFAULT 或 ON 更新子句

【问题讨论】:

  • 它实际上比错误消息看起来要糟糕得多。一旦存在具有TIMESTAMP 数据类型的列,无论是否有额外的子句,您都不能在DEFAULT 或ON UPDATE 子句中定义具有CURRENT_TIMESTAMP 的列!
  • 所以这个工作:CREATE TABLE foo (created_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_on TIMESTAMP),但不是这个:CREATE TABLE foo (updated_on TIMESTAMP, created_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP)
  • @NicolasBuduroi 如果第一个 timestamp 列可以为空,即 null,则不是。如果第一个timestamp 列是not null,则默认情况下会添加DEFAULT CURRENT_TIMESTAMP 和ON UPDATE CURRENT_TIMESTAMP。 stackoverflow.com/a/13544181/2859238
  • @NicolasBuduroi 如果第一个 timestamp 列具有像 default '0000-00-00 00:00:00' 这样的显式默认值集,则也不是。如果该列可以为空或设置了显式默认值,则不会添加DEFAULT CURRENT_TIMESTAMP 和ON UPDATE CURRENT_TIMESTAMP
  • 真的很想知道原因的答案吗?不是如何绕过它或现在如何修复它。为什么会以这种方式实施?这似乎是一种完全脑残的方式,我找不到任何可能成为这种限制的原因的设计/实现。我想学习愚蠢的人如何编程,所以请教我。

标签: mysql timestamp mysql-error-1293


【解决方案1】:

这个限制,只是由于历史,代码遗留的原因,在最近的 MySQL 版本中被取消了:

MySQL 5.6.5 中的更改(2012-04-10,里程碑 8)

以前,每个表最多可以有一个 TIMESTAMP 列 自动初始化或更新为当前日期和时间。 这个限制已经解除。任何 TIMESTAMP 列定义都可以 具有 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE 的任意组合 CURRENT_TIMESTAMP 子句。此外,现在可以使用这些子句 使用 DATETIME 列定义。有关详细信息,请参阅自动 TIMESTAMP 和 DATETIME 的初始化和更新。

http://dev.mysql.com/doc/relnotes/mysql/5.6/en/news-5-6-5.html

【讨论】:

  • 还要检查下面的@mooli 答案。实际上,第一个时间戳列自动设置了“更新 current_timestamp 时的默认 current_timestamp”(因此应该将其命名为 updated_at)。您只需在插入时手动设置 created_at。
  • 如果mysql转储属于5.7版本并且需要在5.4上运行设置怎么办
  • @otc,你可以编辑转储,或者从 5.4 重新开始
【解决方案2】:

很久以前我也想知道。我在我的历史中搜索了一下,我认为这个帖子:http://lists.mysql.com/internals/34919代表了MySQL的半官方立场(在Oracle干预之前;))

简而言之:

此限制仅源于 此功能当前的方式 在服务器和那里实现 没有其他原因 存在。

所以他们的解释是“因为它是这样实现的”。听起来不太科学。我想这一切都来自一些旧代码。这是在上面的线程中建议的:“仅当第一个时间戳字段被自动设置/更新时的结转”。

干杯!

【讨论】:

  • 哇,真臭。希望我们能尽快看到修复。
  • 另一个伟大的 MySQL 限制让我们享受!
  • @gorn 更简单的解决方案/解决方法是下面 Scarlett 提供的解决方案。
【解决方案3】:

我们可以给时间戳一个默认值来避免这个问题。

这篇文章提供了详细的解决方法: http://gusiev.com/2009/04/update-and-create-timestamps-with-mysql/

create table test_table( 
id integer not null auto_increment primary key, 
stamp_created timestamp default '0000-00-00 00:00:00', 
stamp_updated timestamp default now() on update now() 
);

请注意,在“插入”期间,需要在两列中都输入空值:

mysql> insert into test_table(stamp_created, stamp_updated) values(null, null); 
Query OK, 1 row affected (0.06 sec)
mysql> select * from t5; 
+----+---------------------+---------------------+ 
| id | stamp_created       | stamp_updated       |
+----+---------------------+---------------------+
|  2 | 2009-04-30 09:44:35 | 2009-04-30 09:44:35 |
+----+---------------------+---------------------+
2 rows in set (0.00 sec)  
mysql> update test_table set id = 3 where id = 2; 
Query OK, 1 row affected (0.05 sec) Rows matched: 1  Changed: 1  Warnings: 0  
mysql> select * from test_table;
+----+---------------------+---------------------+
| id | stamp_created       | stamp_updated       | 
+----+---------------------+---------------------+ 
|  3 | 2009-04-30 09:44:35 | 2009-04-30 09:46:59 | 
+----+---------------------+---------------------+ 
2 rows in set (0.00 sec) 

【讨论】:

    【解决方案4】:

    确实是实施错误。

    MySQL 中的原生方法是自己更新创建日期(如果您需要)并让 MySQL 担心 时间戳 update date ? update date : creation date,如下所示:

    CREATE TABLE tracked_data( 
      `data` TEXT,
      `timestamp`   TIMESTAMP,
      `creation_date` TIMESTAMP                                   
    ) ENGINE=INNODB; 
    

    在创建时插入 NULL:

    INSERT INTO tracked_data(`data`,`creation_date`) VALUES ('creation..',NULL);
    

    默认情况下,时间戳的 NULL 值作为 CURRENT_TIMESTAMP 进行干预。

    在 MySQL 中,表的第一个 TIMESTAMP 列同时获得 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 属性,如果没有为它提供属性。 这就是为什么带有属性的 TIMESTAMP 列必须放在第一位,否则您会收到此线程中描述的错误。

    【讨论】:

      【解决方案5】:
      1. 将列的数据类型更改为日期时间
      2. 设置触发器

      如:

      DROP TRIGGER IF EXISTS `update_tablename_trigger`;
      DELIMITER //
      CREATE TRIGGER `update_tablename_trigger` BEFORE UPDATE ON `tablename`
       FOR EACH ROW SET NEW.`column_name` = NOW()
      //
      DELIMITER ;
      

      【讨论】:

      • 我一直认为这种方法比半实现的 CURRENT_TIMESTAMP 功能要简单得多。
      【解决方案6】:

      结合各种答案:

      在 MySQL 5.5 中,DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 不能添加到 DATETIME,而只能添加到 TIMESTAMP。

      规则:

      1) 每个表最多有一个TIMESTAMP 列可以自动(或手动[我的添加])初始化或更新为当前日期和时间。 (MySQL 文档)。

      所以在DEFAULT 或ON UPDATE 子句中只有一个TIMESTAMP 可以有CURRENT_TIMESTAMP

      2) 第一个 NOT NULL TIMESTAMP 列没有像 created_date timestamp default '0000-00-00 00:00:00' 这样的显式 DEFAULT 值将被隐式赋予 DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,因此后续的 TIMESTAMP 列不能在 DEFAULT 上被赋予 CURRENT_TIMESTAMP或ON UPDATE 子句

      CREATE TABLE `address` (
        `id` int(9) NOT NULL AUTO_INCREMENT,
        `village` int(11) DEFAULT NULL,
          `created_date` timestamp default '0000-00-00 00:00:00', 
      
          -- Since explicit DEFAULT value that is not CURRENT_TIMESTAMP is assigned for a NOT NULL column, 
          -- implicit DEFAULT CURRENT_TIMESTAMP is avoided.
          -- So it allows us to set ON UPDATE CURRENT_TIMESTAMP on 'updated_date' column.
          -- How does setting DEFAULT to '0000-00-00 00:00:00' instead of CURRENT_TIMESTAMP help? 
          -- It is just a temporary value.
          -- On INSERT of explicit NULL into the column inserts current timestamp.
      
      -- `created_date` timestamp not null default '0000-00-00 00:00:00', // same as above
      
      -- `created_date` timestamp null default '0000-00-00 00:00:00', 
      -- inserting 'null' explicitly in INSERT statement inserts null (Ignoring the column inserts the default value)! 
      -- Remember we need current timestamp on insert of 'null'. So this won't work. 
      
      -- `created_date` timestamp null , // always inserts null. Equally useless as above. 
      
      -- `created_date` timestamp default 0, // alternative to '0000-00-00 00:00:00'
      
      -- `created_date` timestamp, 
      -- first 'not null' timestamp column without 'default' value. 
      -- So implicitly adds DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP. 
      -- Hence cannot add 'ON UPDATE CURRENT_TIMESTAMP' on 'updated_date' column.
      
      
         `updated_date` timestamp null on update current_timestamp,
      
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=132 DEFAULT CHARSET=utf8;
      

      INSERT INTO address (village,created_date) VALUES (100,null);
      

      mysql> select * from address;
      +-----+---------+---------------------+--------------+
      | id  | village | created_date        | updated_date |
      +-----+---------+---------------------+--------------+
      | 132 |     100 | 2017-02-18 04:04:00 | NULL         |
      +-----+---------+---------------------+--------------+
      1 row in set (0.00 sec)
      

      UPDATE address SET village=101 WHERE village=100;
      

      mysql> select * from address;
      +-----+---------+---------------------+---------------------+
      | id  | village | created_date        | updated_date        |
      +-----+---------+---------------------+---------------------+
      | 132 |     101 | 2017-02-18 04:04:00 | 2017-02-18 04:06:14 |
      +-----+---------+---------------------+---------------------+
      1 row in set (0.00 sec)
      

      其他选项(但updated_date 是第一列):

      CREATE TABLE `address` (
        `id` int(9) NOT NULL AUTO_INCREMENT,
        `village` int(11) DEFAULT NULL,
        `updated_date` timestamp null on update current_timestamp,
        `created_date` timestamp not null , 
        -- implicit default is '0000-00-00 00:00:00' from 2nd timestamp onwards
      
        -- `created_date` timestamp not null default '0000-00-00 00:00:00'
        -- `created_date` timestamp
        -- `created_date` timestamp default '0000-00-00 00:00:00'
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=132 DEFAULT CHARSET=utf8;
      

      【讨论】:

        【解决方案7】:

        对您而言,一个解决方法是将其放在 UpdatedDate 字段上,并有一个触发器,仅当 AdditionalDate 为 null 时才使用 UpdatedDate 值更新 AdditionalDate 字段。

        【讨论】:

          【解决方案8】:

          试试这个:

          CREATE TABLE `test_table` (
          `id` INT( 10 ) NOT NULL,
          `created_at` TIMESTAMP NOT NULL DEFAULT 0,
          `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
          ) ENGINE = INNODB;
          

          【讨论】:

          • 这会起作用,但不能解决问题。 created_at 为 0,有点没用。
          • @ComputerEngineer88 这是旧 mysql 服务器的正确解决方案。您应该自己设置created_at 列。我想这就是 op 有意要表达的意思。
          • 这正是官方的解决方案,记录在这里dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html
          【解决方案9】:

          这是 MYSQL 5.5 版本的限制。您需要将版本更新到 5.6。

          Error
          

          我在 MYSQL 中添加表时遇到此错误

          表定义不正确;只能有一个 TIMESTAMP 列 在 DEFAULT 或 ON UPDATE 子句中使用 CURRENT_TIMESTAMP 我的新 MYSQL

          表格看起来像这样。

          create table table_name (col1 int(5) auto_increment 主键,col2 varchar(300), col3 varchar(500), col4 int(3), col5 tinyint(2), col6 时间戳默认 current_timestamp,col7 时间戳默认 current_timestamp 更新 current_timestamp, col8 tinyint(1) 默认 0, col9 tinyint(1) 默认 1);

          在阅读了一些关于不同 MYSQL 版本的变化和一些谷歌搜索之后。我发现 MYSQL 5.6 版比 5.5 版做了一些更改。

          本文将帮助您解决问题。 http://www.oyewiki.com/MYSQL/Incorrect-table-definition-there-can-be-only-one-timestamp-column

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-05-13
            • 1970-01-01
            • 2019-12-09
            • 2012-06-17
            • 2017-04-26
            • 1970-01-01
            • 2022-12-04
            相关资源
            最近更新 更多