Почему в предложении DEFAULT может быть только один столбец TIMESTAMP с CURRENT_TIMESTAMP?


180

Почему может быть только один столбец TIMESTAMP с CURRENT_TIMESTAMP в предложении DEFAULT или ON UPDATE?

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 UPDATE


6
Это на самом деле намного хуже, чем то, что выдает сообщение об ошибке. Вы не можете определить столбец с помощью CURRENT_TIMESTAMPin DEFAULTили ON UPDATEclause, если есть столбец с TIMESTAMPтипом данных, независимо от того, получил ли он дополнительное предложение!
Николас Будурой,

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)
Николас Будурои

@NicolasBuduroi Не , если первый timestampстолбец обнуляемого т.е. null. Если первый timestampстолбец not nullто по умолчанию DEFAULT CURRENT_TIMESTAMPи ON UPDATE CURRENT_TIMESTAMPбудет добавлен. stackoverflow.com/a/13544181/2859238
user104309

@NicolasBuduroi Также нет, если в первом timestampстолбце установлено явное значение по умолчанию, например default '0000-00-00 00:00:00'. Если столбец обнуляемый или явно задано значение по умолчанию, то DEFAULT CURRENT_TIMESTAMPи ON UPDATE CURRENT_TIMESTAMPНЕ будет добавлено
user104309

Очень хотелось бы увидеть ответ о том, почему? не как обойти это или как это исправить сейчас. Почему это когда-либо было реализовано таким образом? Это похоже на тотальный мозговой путь, и я не могу найти дизайн / реализацию, которая могла бы быть причиной этого ограничения. Я хочу узнать, как программируют глупые люди, поэтому, пожалуйста, научите меня.
Лотар

Ответы:


173

Это ограничение, которое было только из-за исторических, наследственных причин кода, было снято в последних версиях MySQL:

Изменения в MySQL 5.6.5 (2012-04-10, Milestone 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). Вам просто нужно установить create_at вручную во время вставки.
Gismo Ranas

что мы можем сделать, если дамп mysql относится к версии 5.7, и установка должна быть запущена на 5.4
otc

1
@otc, вы можете отредактировать дамп или начать заново с 5.4
Jasen

40

Я тоже удивился, что давным-давно. Я немного искал в своей истории, и я думаю, что этот пост: http://lists.mysql.com/internals/34919 представляет полуофициальную позицию MySQL (до вмешательства Oracle;))

Коротко:

это ограничение проистекает только из того, как эта функция в настоящее время реализована на сервере, и нет никаких других причин ее существования.

Таким образом, их объяснение «потому что это реализовано так». Звучит не очень научно. Я думаю, все это происходит из какого-то старого кода. Это предлагается в приведенной выше ветке: «перенос с того момента, когда было установлено / обновлено только первое поле отметки времени».

Ура!


Вау, это действительно воняет. Надеюсь, мы скоро исправим.
BoltClock

46
Еще одно замечательное ограничение MySQL для нас!
Николас Будурой

1
@gorn, более простое решение / обходной путь - это то, что Скарлетт ниже.
TIHE

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_TIMESTAMPи ON 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.
TehShrike

1

Можно исправить это, поместив его в поле updatedDate и запустив триггер, который обновляет поле AddedDate со значением ОбновленоDate, только если AddedDate имеет значение null.


1

Объединяя различные ответы:

В MySQL 5.5 DEFAULT CURRENT_TIMESTAMPи ON UPDATE CURRENT_TIMESTAMPне может быть добавлен, DATETIMEно только включен TIMESTAMP.

Правила:

1) не более одного TIMESTAMPстолбца на таблицу можно автоматически (или вручную [ Моё добавление ]) инициализировать или обновить до текущей даты и времени. (MySQL Docs).

Так что только один TIMESTAMPможет иметь CURRENT_TIMESTAMPв DEFAULTили ON 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_TIMESTAMPв DEFAULTили в 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
Это будет работать, но это не решит проблему. create_at равен 0, что бесполезно.
CompEng88 12.12.14

@ ComputerEngineer88 Это правильное решение для старого сервера MySQL. Вы должны установить created_atколонку самостоятельно. Я думаю, что это то, что я хочу сказать намеренно.
Роджер

это именно официальное решение, задокументированное здесь dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html
Ранги Лин

0

Это ограничение в версии MYSQL 5.5. Вам нужно обновить версию до 5.6.

Error

Я получаю эту ошибку при добавлении таблицы в MYSQL

Неправильное определение таблицы; может быть только один столбец TIMESTAMP с CURRENT_TIMESTAMP в предложении DEFAULT или ON UPDATE Мой новый MYSQL

таблица выглядит примерно так.

создать таблицу 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 и некоторых поисках в Google. Я обнаружил, что в MYSQL версии 5.6 были внесены некоторые изменения по сравнению с версией 5.5.

Эта статья поможет вам решить проблему. http://www.oyewiki.com/MYSQL/Incorrect-table-definition-there-can-be-only-one-timestamp-column

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.