Dlaczego może istnieć tylko jedna kolumna TIMESTAMP z CURRENT_TIMESTAMP w klauzuli DEFAULT?

180

Dlaczego może istnieć tylko jedna kolumna TIMESTAMP z CURRENT_TIMESTAMP w klauzuli DEFAULT lub 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;

Błąd, który powoduje:

Kod błędu: 1293

Niepoprawna definicja tabeli; może być tylko jedna kolumna TIMESTAMP z CURRENT_TIMESTAMP w klauzuli DEFAULT lub ON UPDATE

ripper234
źródło
6
W rzeczywistości jest znacznie gorszy niż komunikat o błędzie, na który wygląda. Nie można zdefiniować kolumnę CURRENT_TIMESTAMPw DEFAULTlub ON UPDATEklauzuli raz tam kolumna z TIMESTAMPtypem danych, bez względu na to, czy to ma dodatkową klauzulę!
Nicolas Buduroi 14.01.11
9
Więc ta praca 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 Nie, jeśli pierwsza timestampkolumna ma wartość zerową, tj null. Jeśli pierwsza timestampkolumna jest not nulldomyślnie DEFAULT CURRENT_TIMESTAMPi ON UPDATE CURRENT_TIMESTAMPzostanie dodana. stackoverflow.com/a/13544181/2859238
user104309
@NicolasBuduroi Również nie, jeśli pierwsza timestampkolumna ma jawną wartość domyślną ustawioną jak default '0000-00-00 00:00:00'. Jeśli kolumna jest pustych lub wyraźnie wartość domyślna jest ustawiona, wtedy DEFAULT CURRENT_TIMESTAMPi ON UPDATE CURRENT_TIMESTAMPnie zostanie dodany
user104309
Naprawdę chciałbym zobaczyć odpowiedź na pytanie dlaczego? nie jak się obejść ani jak to teraz naprawić. Dlaczego zostało to kiedykolwiek wdrożone w ten sposób? Wydaje się, że jest to całkowity sposób braindead i nie mogę znaleźć żadnego projektu / implementacji, który mógłby być przyczyną tego ograniczenia. Chcę się dowiedzieć, jak programują głupi ludzie, więc proszę, naucz mnie.
Lothar

Odpowiedzi:

173

To ograniczenie, które było spowodowane wyłącznie historycznymi, starszymi przyczynami kodu, zostało zniesione w najnowszych wersjach MySQL:

Zmiany w MySQL 5.6.5 (2012-04-10, Kamień milowy 8)

Wcześniej co najwyżej jedna kolumna TIMESTAMP na tabelę mogła być automatycznie inicjowana lub aktualizowana do bieżącej daty i godziny. To ograniczenie zostało zniesione. Każda definicja kolumny TIMESTAMP może mieć dowolną kombinację klauzul DEFAULT CURRENT_TIMESTAMP i ON UPDATE CURRENT_TIMESTAMP. Ponadto klauzule te można teraz stosować z definicjami kolumn DATETIME. Aby uzyskać więcej informacji, zobacz Automatyczna inicjalizacja i aktualizacja dla TIMESTAMP i DATETIME.

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

sierpień
źródło
Sprawdź również odpowiedź @mooli poniżej. W rzeczywistości pierwsza kolumna znacznika czasu ma automatycznie ustawiony „domyślny znacznik_czasu przy aktualizacji bieżący znacznik_czasu” (dlatego należy nazywać ją zaktualizowany_at). Musisz tylko ręcznie ustawić parametr create_at w czasie wstawiania.
Gismo Ranas,
co możemy zrobić, jeśli zrzut mysql należy do wersji 5.7, a konfiguracja musi zostać uruchomiona w wersji 5.4
otc
1
@otc, możesz edytować zrzut lub zacząć od nowa z 5.4
Jasen
40

Zastanawiałem się też dawno temu. Przeszukałem trochę w swojej historii i myślę, że ten post: http://lists.mysql.com/internals/34919 reprezentuje półoficjalne stanowisko MySQL (przed interwencją Oracle;))

W skrócie:

ograniczenie to wynika jedynie ze sposobu, w jaki ta funkcja jest obecnie zaimplementowana na serwerze i nie ma innych powodów jej istnienia.

Ich wyjaśnienie brzmi „ponieważ jest realizowane w ten sposób”. Nie brzmi to zbyt naukowo. Myślę, że wszystko pochodzi od jakiegoś starego kodu. Zasugerowano to w powyższym wątku: „przeniesienie, gdy tylko pierwsze pole znacznika czasu było automatycznie ustawiane / aktualizowane”.

Twoje zdrowie!

Lachezar Balev
źródło
Wow, to naprawdę śmierdzi. Mam nadzieję, że wkrótce zobaczymy poprawkę.
BoltClock
46
Kolejne świetne ograniczenie MySQL, z którego możemy korzystać!
Nicolas Buduroi
1
@orn Łatwiejszym rozwiązaniem / obejściem jest to z Scarlett poniżej.
2013
38

Możemy podać wartość domyślną znacznika czasu, aby uniknąć tego problemu.

Ten post zawiera szczegółowe obejście: 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() 
);

Pamiętaj, że podczas wstawiania należy wprowadzić wartości null do obu kolumn:

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) 
Scarlett
źródło
16

Rzeczywiście błąd implementacji.

Natywne podejście w MySQL polega na tym, aby samodzielnie zaktualizować datę utworzenia (jeśli jest taka potrzeba) i zmusić MySQL do martwienia się o znacznik czasu update date ? update date : creation date :

CREATE TABLE tracked_data( 
  `data` TEXT,
  `timestamp`   TIMESTAMP,
  `creation_date` TIMESTAMP                                   
) ENGINE=INNODB; 

Podczas tworzenia wstaw NULL:

INSERT INTO tracked_data(`data`,`creation_date`) VALUES ('creation..',NULL);

Wartości NULL dla znacznika czasu są domyślnie interpretowane jako CURRENT_TIMESTAMP.

W MySQL pierwsza kolumna TIMESTAMP tabeli otrzymuje oba atrybuty DEFAULT CURRENT_TIMESTAMPi ON UPDATE CURRENT_TIMESTAMPatrybuty, jeśli nie podano dla niego żadnych atrybutów. dlatego kolumna TIMESTAMP z atrybutami musi być pierwsza lub pojawi się błąd opisany w tym wątku.

mooli
źródło
14
  1. Zmień typy danych kolumn na datetime
  2. Ustaw wyzwalacz

Jak na przykład:

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 ;
Feng-Chun Ting
źródło
Zawsze uważałem tę metodę za znacznie mniej szarpiącą niż w połowie zaimplementowana funkcja CURRENT_TIMESTAMP.
TehShrike,
1

Cóż, poprawką może być umieszczenie go w polu UpdatedDate i uruchomienie wyzwalacza, który aktualizuje pole Dodane data o wartości Aktualizowane tylko wtedy, gdy Dodane jest puste.

HLGEM
źródło
1

Łączenie różnych odpowiedzi:

W MySQL 5.5 DEFAULT CURRENT_TIMESTAMPi ON UPDATE CURRENT_TIMESTAMPnie można go dodawać, DATETIMEale tylko na TIMESTAMP.

Zasady:

1) najwyżej jedna TIMESTAMPkolumna na tabelę może być automatycznie (lub ręcznie [ Moje dodanie ]) zainicjowana lub zaktualizowana do bieżącej daty i godziny. (Dokumenty MySQL).

Więc tylko jeden TIMESTAMPmoże mieć CURRENT_TIMESTAMPw DEFAULTlub ON UPDATEklauzulę

2) Pierwsza NOT NULL TIMESTAMPkolumna bez wyraźnej DEFAULTwartości jak created_date timestamp default '0000-00-00 00:00:00'zostaną niejawnie dali DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPi stąd kolejne TIMESTAMPkolumny nie może być udzielona CURRENT_TIMESTAMPna DEFAULTlub ON UPDATEklauzuli

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)

Inna opcja (ale updated_dateto pierwsza kolumna):

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;
użytkownik104309
źródło
0

Spróbuj tego:

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;
Shoaib Qureshi
źródło
3
To zadziała, ale nie rozwiąże problemu. utworzony_at ma wartość 0, co jest dość bezużyteczne.
CompEng88,
@ ComputerEngineer88 To właściwe rozwiązanie dla starego serwera mysql. Powinieneś sam ustawić created_atkolumnę. Myślę, że właśnie to chce powiedzieć celowo.
Roger,
jest to dokładnie oficjalne rozwiązanie, udokumentowane tutaj dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html
Rangi Lin
0

Jest to ograniczenie w wersji MYSQL 5.5. Musisz zaktualizować wersję do 5.6.

Error

Ten błąd pojawiał się podczas dodawania tabeli w MYSQL

Niepoprawna definicja tabeli; może być tylko jedna kolumna TIMESTAMP z CURRENT_TIMESTAMP w klauzuli DEFAULT lub ON UPDATE My new MYSQL

stół wygląda mniej więcej tak.

utwórz tabelę nazwa_tabeli (col1 int (5) auto_increment klucz podstawowy, col2 varchar (300), col3 varchar (500), col4 int (3), col5 tinyint (2), col6 timestamp domyślny current_timestamp, col7 timestamp domyślny current_timestamp przy aktualizacji current_timestamp, col8 tinyint (1) domyślnie 0, col9 tinyint (1) domyślnie 1);

Po pewnym czasie czytania o zmianach w różnych wersjach MYSQL i niektórych googlingach. Dowiedziałem się, że w MYSQL w wersji 5.6 wprowadzono pewne zmiany w stosunku do wersji 5.5.

Ten artykuł pomoże ci rozwiązać problem. http://www.oyewiki.com/MYSQL/Incorrect-table-definition-there-can-be-only-one-timestamp-column

Ankur Rastogi
źródło