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


180

为什么在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

表定义不正确;DEFAULT或ON UPDATE子句中只能有一个带有CURRENT_TIMESTAMP的TIMESTAMP列


6
实际上,它比错误消息看上去要糟糕得多。一旦存在具有数据类型的列,就不能使用CURRENT_TIMESTAMPin DEFAULTON UPDATE子句定义列TIMESTAMP,无论它是否有额外的子句!
Nicolas Buduroi 2011年

9
因此,这项工作:CREATE TABLE foo (created_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_on TIMESTAMP),但不是这样:CREATE TABLE foo (updated_on TIMESTAMP, created_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP)
Nicolas Buduroi 2011年

@NicolasBuduroi如果第一timestamp列是可空的,则不是null。如果第一timestamp列是not null默认值DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP则将添加。stackoverflow.com/a/13544181/2859238
user104309

@NicolasBuduroi如果第一timestamp列具有显式的默认值(例如),则也不是default '0000-00-00 00:00:00'。如果该列可为空或明确设置了默认值DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP则将不会添加该列
user104309

真的很想知道为什么的答案吗?而不是如何解决它或如何对其进行修复。为什么要以这种方式实施?这似乎是一种彻底的死法,我找不到任何可能是这种限制的原因的设计/实现。我想学习愚蠢的人如何编程,所以请教我。
Lothar

Answers:


173

仅由于历史,代码遗留原因,此限制在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。
Gismo Ranas 2015年

如果mysql dump属于5.7版本并且设置需要在5.4上运行,我们该怎么办
otc

1
@otc,您可以编辑转储,或者以5.4重新开始
Jasen

40

我也想知道很久以前。我回顾了一下自己的历史,我认为这篇文章:http : //lists.mysql.com/internals/34919代表了MySQL的半官方地位(在Oracle介入之前)。

简而言之:

此限制仅源于服务器中当前实现此功能的方式,并且没有其他原因存在。

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

干杯!


哇,真臭。希望我们能尽快解决。
BoltClock

46
我们必须享受的另一个MySQL限制!
Nicolas Buduroi 2011年

1
@gorn最简单的解决方案/解决方法是下面的Scarlett。
13年

38

我们可以为时间戳记提供默认值,以避免出现此问题。

这篇文章提供了详细的解决方法: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) 

16

确实是实施错误。

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_TIMESTAMPON UPDATE CURRENT_TIMESTAMP属性。这就是为什么必须首先使用带有属性的TIMESTAMP列,否则您将得到此线程中描述的错误的原因。


14
  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功能要少得多。
2011年

1

很好的解决方法是将其放在UpdatedDate字段上,并有一个触发器,仅当AddedDate为空时,才使用UpdatedDate值来更新AddedDate字段。


1

结合各种答案:

在MySQL 5.5,DEFAULT CURRENT_TIMESTAMP并且ON UPDATE CURRENT_TIMESTAMP不能被添加上DATETIME,但只对TIMESTAMP

规则:

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

所以只有一个TIMESTAMP可以CURRENT_TIMESTAMPDEFAULTON UPDATE子句中使用

2)NOT NULL TIMESTAMP没有显式DEFAULT值的第一列created_date timestamp default '0000-00-00 00:00:00'将被隐式给予a DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,因此后续TIMESTAMP列不能CURRENT_TIMESTAMPDEFAULTor 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;

0

试试这个:

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;

3
这可以工作,但不能解决问题。created_at为0,这是没有用的。
CompEng88

@ ComputerEngineer88这是旧mysql服务器的正确解决方案。您应该created_at自己设置列。我认为这是op想要故意说的。
罗杰

这完全是官方的解决方案,在这里记录dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html
Rangi Lin

0

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

Error

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

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

桌子看起来像这样。

创建表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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.