Наличие столбцов метки времени создания и последнего обновления в MySQL 4.0

127

У меня есть следующая схема таблицы;

CREATE TABLE `db1`.`sms_queue` (
  `Id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `Message` VARCHAR(160) NOT NULL DEFAULT 'Unknown Message Error',
  `CurrentState` VARCHAR(10) NOT NULL DEFAULT 'None',
  `Phone` VARCHAR(14) DEFAULT NULL,
  `Created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `LastUpdated` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP,
  `TriesLeft` tinyint NOT NULL DEFAULT 3,
  PRIMARY KEY (`Id`)
)
ENGINE = InnoDB;

Не удается выполнить следующую ошибку:

ERROR 1293 (HY000): Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause.

У меня вопрос, могу ли я иметь оба этих поля? или мне нужно вручную устанавливать поле LastUpdated во время каждой транзакции?

Ксенф Ян
источник
Привет, @Xenph Yan, не могли бы вы изменить ответ «Принято» с текущего неправильного на правильный? Этот принятый неверный ответ заставил меня потерять около 15 минут, пытаясь понять, что происходит ...
Бруно Рейс
1
@BrunoReis Готово, спасибо за трубку.
Xenph Yan

Ответы:

128

Из документации MySQL 5.5 :

Один столбец TIMESTAMP в таблице может иметь текущую метку времени в качестве значения по умолчанию для инициализации столбца, в качестве значения автообновления или обоих. Невозможно, чтобы текущая метка времени была значением по умолчанию для одного столбца и значением автообновления для другого столбца.

Изменения в MySQL 5.6.5 :

Ранее не более одного столбца TIMESTAMP в таблице можно было автоматически инициализировать или обновлять до текущей даты и времени. Это ограничение снято. Любое определение столбца TIMESTAMP может иметь любую комбинацию предложений DEFAULT CURRENT_TIMESTAMP и ON UPDATE CURRENT_TIMESTAMP. Кроме того, эти предложения теперь можно использовать с определениями столбцов DATETIME. Для получения дополнительной информации см. Автоматическая инициализация и обновление для TIMESTAMP и DATETIME.

Роберт Гэмбл
источник
Это изменилось (по крайней мере, в MySQL 5.0). См. Документацию: dev.mysql.com/doc/refman/5.0/en/timestamp.html
SimonSimCity
Противодействие @SimonSimCity: в документации для 5.0 говорится то же самое, что и выше.
davemyron
5
@RobertGamble Я думаю, что более интересным будет вопрос, ПОЧЕМУ ЧЕРТ, они не предоставили способ сделать эту очень часто запрашиваемую / необходимую функциональность.
Рэй
22
Это кажется немного произвольным со стороны MySQL. Кто-нибудь может объяснить, почему это так?
humble_coder
12
Действительно действительно старый комментарий, НО, он, наконец, был изменен: Changes in MySQL 5.6.5 (2012-04-10, Milestone 8) Previously, at most one TIMESTAMP column per table could be automatically initialized or updated to the current date and time. This restriction has been lifted. Any TIMESTAMP column definition can have any combination of DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP clauses. In addition, these clauses now can be used with DATETIME column definitions. For more information, see Automatic Initialization and Updating for TIMESTAMP and DATETIME.
Маурисио Варгас
83

Есть уловка чтобы иметь обе отметки времени, но с небольшим ограничением.

В одной таблице можно использовать только одно из определений. Создайте оба столбца временных меток следующим образом:

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() 
); 

Обратите внимание, что необходимо ввести nullоба столбца во время insert:

mysql> insert into test_table(stamp_created, stamp_updated) values(null, null); 
Query OK, 1 row affected (0.06 sec)

mysql> select * from test_table; 
+----+---------------------+---------------------+ 
| 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)  
Богдан Гусиев
источник
Вот ссылка из документации MySQL, которая описывает эту функцию: dev.mysql.com/doc/refman/5.0/en/timestamp.html
SimonSimCity
6
первое поле кода, когда вводилось вручную, отлично работало для меня. Спасибо! Мне жаль, что у меня не было достаточно «кармы», чтобы проголосовать за этот ответ, поскольку он спас мой бекон. ммммм спас бекон.
amatusko
Вы должны убедиться, что stamp_created он также установлен как NOT NULL. MySQL автоматически заменит NULL текущей меткой времени.
Валентин Деспа
Почему бы вам также не сделать stamp_createdполе как: stamp_created timestamp default now()вместо использования значения «НУЛЬ»?
Себастьян Шолле
28

Вы можете получить их оба, просто снимите флаг «CURRENT_TIMESTAMP» в созданном поле. Всякий раз, когда вы создаете новую запись в таблице, просто используйте «СЕЙЧАС ()» для значения.

Или.

Напротив, удалите флаг «ON UPDATE CURRENT_TIMESTAMP» и отправьте NOW () для этого поля. В этом есть больше смысла.

Стивен Уолчер
источник
2
Это единственный способ? Я не могу позволить базе данных следить за всеми этими деталями?
Xenph Yan
2
Согласно руководству MySql, CURRENT_TIMESTAMP является синонимом NOW (), поэтому я не думаю, что это сработает.
tvanfosson
Я уверен, что можете, просто CURRENT_TIMESTAMP - это флаг, зарезервированный только для одного поля. В любом случае, если у вас есть этот флаг, независимо от того, какое значение у вас есть для этого поля при добавлении записи, это всегда будет текущая временная метка, отсюда и название.
Стивен Уолчер
1
@tvanfosson: использование NOW () в запросе передает текущее время в базу данных. На самом деле это значение зависит от языка, движка и, вероятно, сотни других вещей, которых я не знаю. Флаг, о котором я говорил, устанавливает так, что при создании записи время добавляется в это поле.
Стивен Уолчер
2
Я использовал способ вставки СЕЙЧАС (), в основном потому, что другой код может касаться этих таблиц, и я не верю, что люди обновят их правильно. :)
Xenph Yan
26

Если вы решили, что MySQL будет обрабатывать обновление временных меток, вы можете настроить триггер для обновления поля при вставке.

CREATE TRIGGER <trigger_name> BEFORE INSERT ON <table_name> FOR EACH ROW SET NEW.<timestamp_field> = CURRENT_TIMESTAMP;

Ссылка на MySQL: http://dev.mysql.com/doc/refman/5.0/en/triggers.html

webkraller
источник
Хорошо, это было то, что я искал. Я не хочу полагаться на людей, добавленных в запрос NOW ()!
Bot
на самом деле было бы лучше сделать после вставки и установить NEW. <timestamp_field> = new. <timestamp_field, которое фактически должно иметь
текущее_время_времени
@KacieHouser Обновление НОВОЙ строки не допускается после триггера
Томас
23

Вот как можно получить автоматические и гибкие поля createDate / lastModified с помощью триггеров:

Сначала определите их так:

CREATE TABLE `entity` (
  `entityid` int(11) NOT NULL AUTO_INCREMENT,
  `createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `lastModified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `name` varchar(255) DEFAULT NULL,
  `comment` text,
  PRIMARY KEY (`entityid`),
)

Затем добавьте эти триггеры:

DELIMITER ;;
CREATE trigger entityinsert BEFORE INSERT ON entity FOR EACH ROW BEGIN SET NEW.createDate=IF(ISNULL(NEW.createDate) OR NEW.createDate='0000-00-00 00:00:00', CURRENT_TIMESTAMP, IF(NEW.createDate<CURRENT_TIMESTAMP, NEW.createDate, CURRENT_TIMESTAMP));SET NEW.lastModified=NEW.createDate; END;;
DELIMITER ;
CREATE trigger entityupdate BEFORE UPDATE ON entity FOR EACH ROW SET NEW.lastModified=IF(NEW.lastModified<OLD.lastModified, OLD.lastModified, CURRENT_TIMESTAMP);
  • Если вы вставляете без указания createDate или lastModified, они будут равны и будут установлены на текущую метку времени.
  • Если вы обновите их без указания createDate или lastModified, для lastModified будет установлена ​​текущая отметка времени.

Но вот что самое приятное:

  • Если вы вставляете , вы можете указать createDate старше, чем текущая метка времени , что позволяет импортировать из более старых времен (lastModified будет равно createDate).
  • Если вы обновляете , вы можете указать lastModified старше предыдущего значения ('0000-00-00 00:00:00' работает хорошо), что позволяет обновить запись, если вы делаете косметические изменения (исправление опечатки в комментарии ) и вы хотите сохранить старую дату lastModified . Это не изменит дату lastModified.
инопланетянин
источник
21

Начиная с MySQL 5.6, это просто ... попробуйте:

create table tweet ( 
    id integer not null auto_increment primary key, 
    stamp_created timestamp default now(), 
    stamp_updated timestamp default now() on update now(),
    message varchar(163)
)
Шахин Гиасси
источник
Вероятно, отличное решение. То, что я ищу, создает и обновляет проблему времени без триггера
matinict
Не могу поверить, что на то, чтобы разрешить эту небольшую неприятность, потребовалось столько времени. Я даже не догадывался, что они это исправили, и сейчас 2018 год ... Спасибо.
hsanders
4

Эта проблема, похоже, была решена в MySQL 5.6. Я заметил это до MySQL 5.5; вот пример кода:

DROP TABLE IF EXISTS `provider_org_group` ;
CREATE TABLE IF NOT EXISTS `provider_org_group` (
  `id` INT NOT NULL,
  `name` VARCHAR(100) NOT NULL,
  `type` VARCHAR(100) NULL,
  `inserted` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `insert_src_ver_id` INT NULL,
  `updated` TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP,
  `update_src_ver_id` INT NULL,
  `version` INT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `id_UNIQUE` (`id` ASC),
  UNIQUE INDEX `name_UNIQUE` (`name` ASC))
ENGINE = InnoDB;

Запуск этого в MySQL 5.5 дает:

ERROR 1293 (HY000): Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause

Запуск в MySQL 5.6

0 row(s) affected   0.093 sec
Kingz
источник
2

Для mysql 5.7.21 я использую следующее и отлично работает:

СОЗДАТЬ ТАБЛИЦУ Posts( modified_atвременная метка НЕ ​​ПУЛЬТ ПО УМОЛЧАНИЮ CURRENT_TIMESTAMP ПРИ ОБНОВЛЕНИИ CURRENT_TIMESTAMP, created_atвременная метка НЕ ​​ПУЛЬТ ПО УМОЛЧАНИЮ CURRENT_TIMESTAMP)

Иоаннис Хрисохос
источник
1

я думаю, что это лучший запрос для stamp_created и stamp_updated

CREATE TABLE test_table( 
    id integer not null auto_increment primary key, 
    stamp_created TIMESTAMP DEFAULT now(), 
    stamp_updated TIMESTAMP DEFAULT '0000-00-00 00:00:00' ON UPDATE now() 
); 

потому что при создании записи stamp_createdдолжен быть заполнен now()и stamp_updatedдолжен быть заполнен'0000-00-00 00:00:00'

Anonim-
источник