Маючи як створені, так і останні оновлені стовпці часових позначок у 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.

Моє запитання: чи можу я мати обидва ці поля? чи мені вручну встановлювати поле LastUpdate під час кожної транзакції?


Гей, @Xenph Yan, ти не проти змінити відповідь "Прийнято" з поточної неправильної на правильну? Ця прийнята, неправильна відповідь змусила мене приблизно 15 хвилин, намагаючись зрозуміти, що відбувається ...
Бруно Рейс

1
@BrunoReis Готово, дякую за підбір.
Ксенф Ян

Відповіді:


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 говорять точно так само, як вище.
Деймірон

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()замість використання значення "ZERO"?
Себастьян Шолль

28

Ви можете мати їх обох, просто зніміть прапор "CURRENT_TIMESTAMP" на створеному полі. Щоразу, коли ви створюєте новий запис у таблиці, просто використовуйте "NOW ()" для значення.

Або

Навпаки, видаліть прапор 'ON UPDATE CURRENT_TIMESTAMP' і надішліть NOW () для цього поля. Цей спосіб насправді має більше сенсу.


2
Це єдиний спосіб? Я не можу доглядати за цією деталлю в базі даних?
Ксенф Ян

2
Відповідно до посібника MySql, CURRENT_TIMESTAMP є синонімом NOW (), тому я не думаю, що це спрацює.
tvanfosson

Я впевнений, що ви можете, це просто CURRENT_TIMESTAMP - прапор, зарезервований лише для одного поля. У будь-якому випадку, якщо у вас був цей прапор, незалежно від того, яке значення ви маєте для цього поля, коли ви додаєте запис, воно завжди буде поточною міткою часу, звідси і назва.
Стівен Уолчер

1
@tvanfosson: Використання 'NOW ()' у запиті передає поточний час до бази даних. Яке значення має насправді, залежить від мови, двигуна та, мабуть, сотні інших речей, яких я не знаю. Прапор, про який я мав на увазі, встановлює його так, що коли створюється запис, до цього поля додається час.
Стівен Уолчер

2
Я пішов із вставкою ЗАРАЗ (), головним чином, оскільки інший код може торкатися цих таблиць, і я не довіряю людям правильно їх оновити. :)
Ксенф Ян

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/uk/triggers.html


Приємно це було те, що я шукав. Мені не хочеться покладатися на людей, які додали ЗАРАЗ () у запит!
Бот

насправді було б краще зробити після вставки та встановити НОВО. <timestamp_field> = new. <timestamp_field, який насправді повинен мати типовий current_timestamp> таким чином, обидва поля є
постійними

@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, остання зміна буде встановлена ​​на поточну позначку часу.

Але ось приємна частина:

  • Якщо ви вставите , ви можете вказати createDate, старший за поточну часову позначку , що дозволить імпорту зі старих часів працювати добре (lastModified буде дорівнює createDate).
  • Якщо ви оновлюєтесь , ви можете вказати lastModified старше попереднього значення ("0000-00-00 00:00:00" працює добре), що дозволяє оновити запис, якщо ви робите косметичні зміни (виправляючи помилку в коментарі ), і ви хочете зберегти стару останню змінену дату. Це не змінить дату останньої модифікації.

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

Можливо, чудове рішення Що я шукаю, створюю та
оновлюю

Я не можу повірити, що пройшло так багато часу, щоб ця маленька неприємність була вирішена. Я навіть не здогадувався, що вони це виправили, і це 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


2

Для mysql 5.7.21 я використовую наступне та чудово працює:

СТВОРИТИ ТАБЛИЦЮ Posts( modified_atчасова марка НЕ ​​НУЛЬКОГО ЗАМОВЛЕННЯ CURRENT_TIMESTAMP НА ОНОВЛЕННЯ CURRENT_TIMESTAMP, created_atчасова марка НЕ ​​NULL DEFAULT CURRENT_TIMESTAMP)


1

Я думаю, що це кращий запит для stamp_create та stamp_update

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'


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.