Warum kann die DEFAULT-Klausel nur eine TIMESTAMP-Spalte mit CURRENT_TIMESTAMP enthalten?

179

Warum kann es in der DEFAULT- oder ON UPDATE-Klausel nur eine TIMESTAMP-Spalte mit CURRENT_TIMESTAMP geben?

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;

Der daraus resultierende Fehler:

Fehlercode: 1293

Falsche Tabellendefinition; Es kann nur eine TIMESTAMP-Spalte mit CURRENT_TIMESTAMP in der DEFAULT- oder ON UPDATE-Klausel geben

ripper234
quelle
6
Es ist tatsächlich viel schlimmer als die Fehlermeldung, die es aussehen lässt. Sie können eine Spalte mit CURRENT_TIMESTAMPin DEFAULToder ON UPDATE-Klausel nicht definieren TIMESTAMP, wenn es eine Spalte mit Datentyp gibt, unabhängig davon, ob sie eine zusätzliche Klausel enthält!
Nicolas Buduroi
9
Also diese Arbeit: CREATE TABLE foo (created_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_on TIMESTAMP)aber nicht diese:CREATE TABLE foo (updated_on TIMESTAMP, created_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP)
Nicolas Buduroi
@NicolasBuduroi Nicht, wenn die erste timestampSpalte nullbar ist, dh null. Wenn die erste timestampSpalte not nulldann standardmäßig ist DEFAULT CURRENT_TIMESTAMPund ON UPDATE CURRENT_TIMESTAMPhinzugefügt wird. stackoverflow.com/a/13544181/2859238
user104309
@NicolasBuduroi Auch nicht, wenn für die erste timestampSpalte ein expliziter Standardwert wie festgelegt ist default '0000-00-00 00:00:00'. Wenn die Spalte NULL - Werte zulässt oder explizit Standardwert festgelegt ist, dann DEFAULT CURRENT_TIMESTAMPund ON UPDATE CURRENT_TIMESTAMPwird nicht hinzugefügt werden
user104309
Würde wirklich gerne eine Antwort über das Warum sehen? nicht, wie man es umgeht oder wie es jetzt behoben ist. Warum wurde dies jemals auf diese Weise umgesetzt? Es scheint ein totaler Braindead-Weg zu sein und ich kann kein Design / keine Implementierung finden, die möglicherweise ein Grund für diese Einschränkung sein könnte. Ich möchte lernen, wie dumme Leute programmieren, also lehre mich bitte.
Lothar

Antworten:

172

Diese Einschränkung, die nur aus historischen Gründen des Code-Legacy bestand, wurde in neueren Versionen von MySQL aufgehoben:

Änderungen in MySQL 5.6.5 (2012-04-10, Meilenstein 8)

Bisher konnte höchstens eine TIMESTAMP-Spalte pro Tabelle automatisch initialisiert oder auf das aktuelle Datum und die aktuelle Uhrzeit aktualisiert werden. Diese Einschränkung wurde aufgehoben. Jede TIMESTAMP-Spaltendefinition kann eine beliebige Kombination der Klauseln DEFAULT CURRENT_TIMESTAMP und ON UPDATE CURRENT_TIMESTAMP enthalten. Außerdem können diese Klauseln jetzt mit DATETIME-Spaltendefinitionen verwendet werden. Weitere Informationen finden Sie unter Automatische Initialisierung und Aktualisierung für TIMESTAMP und DATETIME.

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

Augustin
quelle
Überprüfen Sie auch die Antwort von @mooli unten. Tatsächlich wird in der ersten Zeitstempelspalte automatisch "Standardstromstempel beim Aktualisieren des aktuellen Zeitstempels" festgelegt (daher sollte der Name "update_at" lauten). Sie müssen create_at nur zum Einfügezeitpunkt manuell einstellen.
Gismo Ranas
Was können wir tun, wenn der MySQL-Dump zu einer 5.7-Version gehört und das Setup auf einem 5.4
otc
1
@otc, Sie könnten den Dump bearbeiten oder erneut mit 5.4
Jasen
40

Das habe ich mich auch schon vor langer Zeit gefragt. Ich habe ein bisschen in meiner Geschichte gesucht und denke, dass dieser Beitrag: http://lists.mysql.com/internals/34919 die halboffizielle Position von MySQL darstellt (vor der Intervention von Oracle;))

Zusamenfassend:

Diese Einschränkung ergibt sich nur aus der Art und Weise, wie diese Funktion derzeit auf dem Server implementiert ist, und es gibt keine anderen Gründe für ihre Existenz.

Ihre Erklärung lautet also "weil es so implementiert ist". Klingt nicht sehr wissenschaftlich. Ich denke, alles kommt von einem alten Code. Dies wird im obigen Thread vorgeschlagen: "Übertragung von, als nur das erste Zeitstempelfeld automatisch gesetzt / aktualisiert wurde".

Prost!

Lachezar Balev
quelle
Wow, das stinkt wirklich. Hoffe wir sehen bald eine Lösung.
BoltClock
46
Eine weitere großartige MySQL-Einschränkung, die wir genießen können!
Nicolas Buduroi
1
@gorn Die einfachere Lösung / Umgehung ist die von Scarlett unten.
Bis
38

Wir können einen Standardwert für den Zeitstempel angeben, um dieses Problem zu vermeiden.

Dieser Beitrag enthält eine detaillierte Problemumgehung: 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() 
);

Beachten Sie, dass beim "Einfügen" in beide Spalten Nullen eingegeben werden müssen:

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
quelle
16

In der Tat ein Implementierungsfehler.

Der native Ansatz in MySQL besteht darin, ein Erstellungsdatum selbst zu aktualisieren (falls Sie eines benötigen) und MySQL sich über den Zeitstempel update date ? update date : creation date wie folgt Gedanken zu machen :

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

Bei der Erstellung NULL einfügen:

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

NULL-Werte für den Zeitstempel werden standardmäßig als CURRENT_TIMESTAMP interpretiert.

In MySQL erhält die erste TIMESTAMP-Spalte einer Tabelle sowohl das Attribut DEFAULT CURRENT_TIMESTAMPals auch das ON UPDATE CURRENT_TIMESTAMPAttribut, wenn keine Attribute dafür angegeben sind. Aus diesem Grund muss die TIMESTAMP-Spalte mit den Attributen an erster Stelle stehen. Andernfalls wird der in diesem Thread beschriebene Fehler angezeigt.

Mooli
quelle
14
  1. Ändern Sie die Datentypen von Spalten in datetime
  2. Trigger setzen

Sowie:

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
quelle
Ich habe diese Methode immer als viel weniger nervös angesehen als die halb implementierte CURRENT_TIMESTAMP-Funktionalität.
TheShrike
1

Eine Lösung für Sie könnte darin bestehen, es in das Feld UpdatedDate einzufügen und einen Trigger zu haben, der das Feld AddedDate nur dann mit dem Wert UpdatedDate aktualisiert, wenn AddedDate null ist.

HLGEM
quelle
1

Verschiedene Antworten kombinieren:

In MySQL 5.5 DEFAULT CURRENT_TIMESTAMPund ON UPDATE CURRENT_TIMESTAMPkann nicht hinzugefügt werden, DATETIMEsondern nur auf TIMESTAMP.

Regeln:

1) höchstens eine TIMESTAMPSpalte pro Tabelle kann automatisch (oder manuell [ Meine Hinzufügung ]) initialisiert oder auf das aktuelle Datum und die aktuelle Uhrzeit aktualisiert werden. (MySQL Docs).

Also nur eine TIMESTAMPhaben kann CURRENT_TIMESTAMPin DEFAULToder ON UPDATEKlausel

2) Die erste NOT NULL TIMESTAMPSpalte ohne einen expliziten DEFAULTWert wie created_date timestamp default '0000-00-00 00:00:00'implizit eine gegeben werden DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPund somit nachfolgende TIMESTAMPSpalten können nicht gegeben werden CURRENT_TIMESTAMPauf DEFAULToder ON UPDATEKlausel

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)

Andere Option (aber updated_dateist die erste Spalte):

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;
user104309
quelle
0

Versuche dies:

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
quelle
3
Dies wird funktionieren, aber es löst das Problem nicht. created_at ist 0, was irgendwie nutzlos ist.
CompEng88
@ ComputerEngineer88 Dies ist die richtige Lösung für alte MySQL-Server. Sie sollten die created_atSpalte selbst festlegen . Ich denke, das ist es, was ich absichtlich sagen möchte.
Roger
Dies ist genau die offizielle Lösung, die hier dokumentiert ist. dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html
Rangi Lin
0

Dies ist die Einschränkung in der MYSQL 5.5-Version. Sie müssen die Version auf 5.6 aktualisieren.

Error

Ich habe diesen Fehler beim Hinzufügen einer Tabelle in MYSQL erhalten

Falsche Tabellendefinition; Es kann nur eine TIMESTAMP-Spalte mit CURRENT_TIMESTAMP in der DEFAULT- oder ON UPDATE-Klausel My new MYSQL geben

Tisch sieht ungefähr so ​​aus.

Erstellen Sie die Tabelle tabellenname (col1 int (5) auto_increment primärschlüssel, col2 varchar (300), col3 varchar (500), col4 int (3), col5 tinyint (2), col6 timestamp default current_timestamp, col7 timestamp default current_timestamp bei update current_timestamp, col8 tinyint (1) Standard 0, col9 tinyint (1) Standard 1);

Nach einiger Zeit des Lesens über Änderungen in verschiedenen MYSQL-Versionen und einige der googeln. Ich fand heraus, dass in MYSQL Version 5.6 gegenüber Version 5.5 einige Änderungen vorgenommen wurden.

Dieser Artikel hilft Ihnen bei der Behebung des Problems. http://www.oyewiki.com/MYSQL/Incorrect-table-definition-there-can-be-only-one-timestamp-column

Ankur Rastogi
quelle