Sowohl eine erstellte als auch eine zuletzt aktualisierte Zeitstempelspalte in MySQL 4.0

127

Ich habe das folgende Tabellenschema;

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;

Es schlägt mit folgendem Fehler fehl:

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

Meine Frage ist, kann ich beide Felder haben? oder muss ich bei jeder Transaktion manuell ein LastUpdated-Feld festlegen?

Xenph Yan
quelle
Hey, @Xenph Yan, würde es Ihnen etwas ausmachen, die "Akzeptierte" Antwort von der aktuellen falschen in die richtige zu ändern? Diese akzeptierte, falsche Antwort ließ mich ungefähr 15 Minuten verlieren, um herauszufinden, was geschah ...
Bruno Reis
1
@BrunoReis Fertig, danke für die Abholung.
Xenph Yan

Antworten:

128

Aus der MySQL 5.5- Dokumentation :

Eine TIMESTAMP-Spalte in einer Tabelle kann den aktuellen Zeitstempel als Standardwert für die Initialisierung der Spalte, als Wert für die automatische Aktualisierung oder beides haben. Es ist nicht möglich, dass der aktuelle Zeitstempel der Standardwert für eine Spalte und der Wert für die automatische Aktualisierung für eine andere Spalte ist.

Änderungen in MySQL 5.6.5 :

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.

Robert Gamble
quelle
Das hat sich geändert (zumindest in MySQL 5.0). Siehe die Dokumentation: dev.mysql.com/doc/refman/5.0/en/timestamp.html
SimonSimCity
Countering @SimonSimCity: Die Dokumente für 5.0 sagen genau dasselbe wie oben.
Davemyron
5
@RobertGamble Ich denke, die interessantere Frage wäre, WARUM DER HECK NICHT, dass sie keine Möglichkeit zur Durchführung dieser sehr häufig angeforderten / benötigten Funktionalität bereitgestellt haben.
Ray
22
Dies scheint seitens MySQL etwas willkürlich zu sein. Kann jemand erklären, warum dies der Fall ist?
bescheidene_coder
12
Wirklich wirklich alter Kommentar, ABER, es wurde endlich geändert: 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.
Mauricio Vargas
83

Es gibt einen Trick , beide Zeitstempel zu haben, aber mit einer kleinen Einschränkung.

Sie können nur eine der Definitionen in einer Tabelle verwenden. Erstellen Sie beide Zeitstempelspalten wie folgt:

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 Sie nullin beide Spalten eingeben müssen , während 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)  
Bogdan Gusiev
quelle
Hier ist ein Link aus der MySQL-Dokumentation, der diese Funktion beschreibt: dev.mysql.com/doc/refman/5.0/en/timestamp.html
SimonSimCity
6
Das erste Codefeld, wenn es manuell eingegeben wurde, funktionierte perfekt für mich. Vielen Dank! Ich wünschte, ich hätte genug "Karma", um diese Antwort zu verbessern, da sie meinen Speck rettete. mmmmm Speck gespart.
Amatusko
Sie müssen sicherstellen, dass dies stamp_created auch als NOT NULL festgelegt ist. MySQL ersetzt automatisch NULL durch den aktuellen Zeitstempel.
Valentin Despa
Warum machen Sie das stamp_createdFeld nicht auch wie stamp_created timestamp default now()folgt : anstatt einen 'ZERO'-Wert zu verwenden?
Sebastian Scholle
28

Sie können beide haben, entfernen Sie einfach das Flag "CURRENT_TIMESTAMP" im erstellten Feld. Wenn Sie einen neuen Datensatz in der Tabelle erstellen, verwenden Sie einfach "NOW ()" für einen Wert.

Oder.

Entfernen Sie im Gegenteil das Flag 'ON UPDATE CURRENT_TIMESTAMP' und senden Sie das NOW () für dieses Feld. Dieser Weg macht eigentlich mehr Sinn.

Stephen Walcher
quelle
2
Ist das der einzige Weg? Ich kann die Datenbank nicht nach all diesen Details suchen lassen?
Xenph Yan
2
Laut dem MySQL-Handbuch ist CURRENT_TIMESTAMP ein Synonym für NOW (), daher denke ich nicht, dass dies funktionieren wird.
Tvanfosson
Ich bin sicher, Sie können, es ist nur so, dass CURRENT_TIMESTAMP ein Flag ist, das nur für ein Feld reserviert ist. In beiden Fällen ist es immer der aktuelle Zeitstempel, daher der Name, wenn Sie dieses Flag dort hatten, unabhängig davon, welchen Wert Sie für dieses Feld haben, wenn Sie einen Datensatz hinzufügen.
Stephen Walcher
1
@tvanfosson: Wenn Sie 'NOW ()' in einer Abfrage verwenden, wird die aktuelle Zeit an die Datenbank übergeben. Was dieser Wert tatsächlich ist, hängt von der Sprache, der Engine und wahrscheinlich hundert anderen Dingen ab, die ich nicht kenne. Das Flag, auf das ich mich bezog, setzt es so, dass beim Erstellen eines Datensatzes die Zeit zu diesem Feld hinzugefügt wird.
Stephen Walcher
2
Ich habe mich für NOW () entschieden, vor allem, weil anderer Code diese Tabellen möglicherweise berührt und ich nicht vertraue, dass die Leute sie korrekt aktualisieren. :)
Xenph Yan
26

Wenn Sie sich dafür entscheiden, dass MySQL die Aktualisierung von Zeitstempeln übernimmt, können Sie einen Trigger einrichten, um das Feld beim Einfügen zu aktualisieren.

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

MySQL-Referenz: http://dev.mysql.com/doc/refman/5.0/en/triggers.html

Webkraller
quelle
Schön, dass ich danach gesucht habe. Ich möchte mich nicht auf Leute verlassen müssen, die JETZT () zur Abfrage hinzugefügt wurden!
Bot
Eigentlich wäre es besser, nach dem Einfügen NEU zu setzen. <Zeitstempelfeld> = neu. <Zeitstempelfeld, das tatsächlich den Standard-Zeitstempel aktuell haben muss> Auf diese Weise sind beide Felder konsistent
KacieHouser
@ KacieHouser Das Aktualisieren der NEUEN Zeile ist nach dem Auslösen nicht zulässig
Thomas
23

So können Sie mithilfe von Triggern automatische und flexible createDate / lastModified-Felder erstellen:

Definieren Sie sie zuerst so:

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

Fügen Sie dann diese Trigger hinzu:

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);
  • Wenn Sie einfügen ohne Angabe ErstellDat oder lastModified, werden sie auf dem aktuellen Zeitstempel gleich und eingestellt werden.
  • Wenn Sie sie aktualisieren , ohne createDate oder lastModified anzugeben, wird lastModified auf den aktuellen Zeitstempel gesetzt.

Aber hier ist der schöne Teil:

  • Wenn Sie einfügen , können Sie ein Erstellungsdatum angeben, das älter als der aktuelle Zeitstempel ist , sodass Importe aus älteren Zeiten gut funktionieren (lastModified entspricht createDate).
  • Wenn Sie aktualisieren , können Sie ein lastModified angeben, das älter als der vorherige Wert ist ('0000-00-00 00:00:00' funktioniert gut), sodass ein Eintrag aktualisiert werden kann, wenn Sie kosmetische Änderungen vornehmen (Beheben eines Tippfehlers in einem Kommentar) ) und Sie möchten das alte lastModified- Datum beibehalten . Dadurch wird das Datum der letzten Änderung nicht geändert.
Außerirdischer
quelle
21

Ab MySQL 5.6 ist es einfach ... probieren Sie es aus:

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)
)
Shaheen Ghiassy
quelle
Wahrscheinlich großartige Lösung Was ich
suche
Ich kann nicht glauben, dass es so lange gedauert hat, bis dieses kleine Ärgernis behoben war. Ich wusste nicht einmal, dass sie das behoben hatten und es ist 2018 ... Danke.
Hsanders
4

Dieses Problem schien in MySQL 5.6 behoben worden zu sein. Ich habe dies bis MySQL 5.5 bemerkt; Hier ist ein Beispielcode:

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;

Wenn Sie dies unter MySQL 5.5 ausführen, erhalten Sie:

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

Führen Sie dies unter MySQL 5.6 aus

0 row(s) affected   0.093 sec
Kingz
quelle
2

Für MySQL 5.7.21 verwende ich Folgendes und funktioniert gut:

CREATE TABLE Posts( modified_atZeitstempel NICHT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, created_atZeitstempel NICHT NULL DEFAULT CURRENT_TIMESTAMP)

Ioannis Chrysochos
quelle
1

Ich denke, dies ist die bessere Abfrage für stamp_created und 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() 
); 

denn wenn der Datensatz erstellt wird, stamp_createdsollte gefüllt werden von now()und stamp_updatedsollte gefüllt werden von'0000-00-00 00:00:00'

Anonim-
quelle