Чому в пункті 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 UPDATEпісля того, як з'явиться стовпець з TIMESTAMPтипом даних, незалежно від того, отримав він додатковий пункт!
Nicolas Buduroi

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, етап 8)

Раніше щонайбільше один стовпець TIMESTAMP на таблицю міг бути автоматично ініціалізований або оновлений до поточної дати та часу. Це обмеження було знято. Будь-яке визначення стовпця TIMESTAMP може мати будь-яку комбінацію пропозицій DEFAULT CURRENT_TIMESTAMP та ON UPDATE CURRENT_TIMESTAMP. Крім того, ці пропозиції тепер можна використовувати з визначеннями стовпців DATETIME. Для отримання додаткової інформації див. Автоматичну ініціалізацію та оновлення для TIMESTAMP та DATETIME.

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


Також перевірте відповідь @mooli нижче. Насправді перший стовпець часової позначки автоматично встановлює "default_timestamp on update current_timestamp" (тому його слід називати оновленим_at). Вам просто потрібно встановити create_at вручну під час вставки.
Gismo Ranas

що ми можемо зробити , якщо MySQL дамп відноситься до версії 5.7 , а установка повинна бути запущена на 5,4
OTC

1
@otc, ви можете відредагувати дамп або почати заново з 5.4.
Ясен

40

Я теж дивувався тому давно. Я трохи шукав в своїй історії, і вважаю, що цей пост: http://lists.mysql.com/internals/34919 являє собою офіційну позицію MySQL (до втручання Oracle;))

Коротко:

це обмеження випливає лише з того, яким чином ця функція реалізується в даний час на сервері, і немає інших причин її існування.

Тож їх пояснення полягає в тому, що "тому, що воно реалізоване так". Це не дуже науково. Я здогадуюсь, це все походить із якогось старого коду. Це пропонується у потоці вище: "перенесення з того часу, коли було встановлено / оновлено лише перше поле часової позначки".

Ура!


Ого, це справді смердить. Сподіваємось, ми скоро побачимо виправлення.
BoltClock

46
Ще одне велике обмеження MySQL для нас!
Nicolas Buduroi

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; 

При створенні Insert 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

Добре виправленням для вас може бути розміщення його в полі UpdateDate та наявність тригера, який оновлює поле AddDate зі значенням UpdateDate лише у тому випадку, якщо додаток "zeroDate" є недійсним.


1

Поєднання різних відповідей:

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

Правила:

1) максимум один TIMESTAMPстовпчик на таблиці може бути автоматично (або вручну [ Моє додавання ]) ініціалізовано або оновлено до поточної дати та часу. (Документи MySQL).

Отже, лише один TIMESTAMPможе мати CURRENT_TIMESTAMPв собі DEFAULTабо ON UPDATEзастереження

2) Перший NOT NULL TIMESTAMPстовпець без явного DEFAULTзначення , як created_date timestamp default '0000-00-00 00:00:00'буде неявно заданий 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
Це буде працювати, але це не вирішує проблему. created_at дорівнює 0, що є марним.
CompEng88

@ ComputerEngineer88 Це правильне рішення для старого сервера mysql. Ви повинні встановити created_atстовпчик самостійно. Я думаю, що це хочу сказати навмисно.
Роджер

це саме офіційне рішення, задокументоване тут dev.mysql.com/doc/refman/5.5/uk/timestamp-initialization.html
Lin

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 timetamp за замовчуванням current_timestamp за оновлення current_timestamp, col8 tinyint (1) за замовчуванням 0, col9 tinyint (1) за замовчуванням 1);

Через деякий час читайте про зміни в різних версіях MYSQL та деякі з googling. Я з’ясував, що в 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.