Avere sia una colonna di data di creazione sia quella dell'ultimo aggiornamento in MySQL 4.0


127

Ho il seguente schema di tabella;

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;

Non riesce con il seguente errore:

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

La mia domanda è: posso avere entrambi quei campi? o devo impostare manualmente un campo LastUpdated durante ogni transazione?


Ehi, @Xenph Yan, ti dispiacerebbe cambiare la risposta "Accettata" dall'attuale sbagliata a quella giusta? Questa risposta accettata e sbagliata mi ha fatto perdere circa 15 minuti cercando di capire cosa stesse succedendo ...
Bruno Reis,

1
@BrunoReis Fatto, grazie per il ritiro.
Xenph Yan,

Risposte:


128

Dalla documentazione di MySQL 5.5 :

Una colonna TIMESTAMP in una tabella può avere il timestamp corrente come valore predefinito per l'inizializzazione della colonna, come valore di aggiornamento automatico o entrambi. Non è possibile avere il timestamp corrente come valore predefinito per una colonna e il valore di aggiornamento automatico per un'altra colonna.

Modifiche in MySQL 5.6.5 :

In precedenza, al massimo una colonna TIMESTAMP per tabella poteva essere inizializzata o aggiornata automaticamente alla data e ora correnti. Questa limitazione è stata revocata. Qualsiasi definizione di colonna TIMESTAMP può avere qualsiasi combinazione di clausole DEFAULT CURRENT_TIMESTAMP e ON UPDATE CURRENT_TIMESTAMP. Inoltre, queste clausole ora possono essere utilizzate con le definizioni delle colonne DATETIME. Per ulteriori informazioni, vedere Inizializzazione e aggiornamento automatici per TIMESTAMP e DATETIME.


Questo è cambiato (almeno in MySQL 5.0). Vedere la documentazione: dev.mysql.com/doc/refman/5.0/en/timestamp.html
SimonSimCity

Contrastando @SimonSimCity: i documenti per 5.0 dicono esattamente la stessa cosa di cui sopra.
davemyron,

5
@RobertGamble Penso che la domanda più interessante sarebbe PERCHÉ IL DIAVOLO NON hanno fornito un modo per fare questa funzionalità molto richiesta / necessaria.
Ray

22
Questo sembra un po 'arbitrario da parte di MySQL. Qualcuno può spiegare perché questo è il caso?
humble_coder

12
Commento davvero molto vecchio, MA alla fine è stato modificato: 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 il

83

C'è un trucco per avere entrambi i timestamp, ma con un piccolo limite.

È possibile utilizzare solo una delle definizioni in una tabella. Crea entrambe le colonne del timestamp in questo modo:

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

Si noti che è necessario entrare nullin entrambe le colonne durante 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)  

Ecco un link dalla documentazione di MySQL che descrive quella funzione: dev.mysql.com/doc/refman/5.0/en/timestamp.html
SimonSimCity

6
la prima casella di codice, quando inserita manualmente ha funzionato perfettamente per me. Grazie! Vorrei avere abbastanza "karma" per votare questa risposta perché mi ha salvato la pancetta. pancetta salvata mmmmm.
amatusko,

È necessario assicurarsi che stamp_created sia impostato anche come NOT NULL. MySQL sostituirà automaticamente il NULL con il timestamp corrente.
Valentin Despa,

Perché non crei anche il stamp_createdcampo come: stamp_created timestamp default now()invece di usare un valore 'ZERO'?
Sebastian Scholle,

28

Puoi averli entrambi, basta togliere il flag "CURRENT_TIMESTAMP" sul campo creato. Ogni volta che crei un nuovo record nella tabella, usa "NOW ()" per un valore.

O.

Al contrario, rimuovere il flag "ON UPDATE CURRENT_TIMESTAMP" e inviare NOW () per quel campo. In questo modo in realtà ha più senso.


2
È questo l'unico modo? Non posso fare in modo che il database si occupi di tutti quei dettagli?
Xenph Yan,

2
Secondo il manuale di MySql, CURRENT_TIMESTAMP è sinonimo di NOW (), quindi non credo che funzionerà.
Tvanfosson,

Sono sicuro che puoi, è solo che CURRENT_TIMESTAMP è una bandiera riservata a un solo campo. Ad ogni modo, se avessi quel flag lì dentro, indipendentemente dal valore che hai per quel campo quando aggiungi un record, sarà sempre il timestamp corrente, quindi il nome.
Stephen Walcher,

1
@tvanfosson: l'uso di 'NOW ()' in una query trasmette l'ora corrente al database. Quale sia effettivamente quel valore dipende dalla lingua, dal motore e probabilmente da un centinaio di altre cose che non conosco. Il flag a cui mi riferivo lo imposta in modo che quando viene creato un record, il tempo viene aggiunto a quel campo.
Stephen Walcher,

2
Sono andato con l'inserimento NOW (), principalmente perché altri codici potrebbero toccare queste tabelle e non mi fido delle persone che li aggiornino correttamente. :)
Xenph Yan,

26

Se decidi di fare in modo che MySQL gestisca l'aggiornamento dei timestamp, puoi impostare un trigger per aggiornare il campo al momento dell'inserimento.

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

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


Bello questo era quello che stavo cercando. Non voglio fare affidamento sulle persone aggiunte ADESSO () alla query!
Bot,

in realtà sarebbe meglio farlo dopo aver inserito, e impostare NEW. <timestamp_field> = new. <timestamp_field che in realtà deve avere l'attuale current_timestamp> in questo modo entrambi i campi sono
coerenti

@KacieHouser L'aggiornamento della NUOVA riga non è consentito dopo il trigger
Thomas

23

Ecco come si possono avere campi createDate / lastModified automatici e flessibili usando i trigger:

Per prima cosa definiscili in questo modo:

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

Quindi aggiungere questi trigger:

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);
  • Se si inserisce senza specificare createDate o lastModified, saranno uguali e impostati sul timestamp corrente.
  • Se li aggiorni senza specificare createDate o lastModified, lastModified verrà impostato sul timestamp corrente.

Ma ecco la bella parte:

  • Se si inserisce , è possibile specificare un createDate più vecchio del timestamp corrente , consentendo alle importazioni di tempi precedenti di funzionare correttamente (lastModified sarà uguale a createDate).
  • Se aggiorni , puoi specificare un ultimo Modificato più vecchio del valore precedente ("registrazione 00:00:00" funziona bene), consentendo di aggiornare una voce se stai apportando modifiche estetiche (correggendo un refuso in un commento ) e desideri mantenere la vecchia data dell'ultimo modificato . Ciò non modificherà la data dell'ultima modifica.

21

A partire da MySQL 5.6 è facile ... provalo:

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

Probabilmente un'ottima soluzione Quello che sto cercando di creare e aggiornare il problema del tempo senza trigger
matinict

Non riesco a credere che ci sia voluto così tanto tempo per risolvere questo piccolo fastidio. Non avevo nemmeno capito che avevano risolto questo problema ed è il 2018 ... Grazie.
hsanders,

4

Questo problema sembrava essere stato risolto in MySQL 5.6. Ho notato questo fino a MySQL 5.5; ecco un esempio di codice:

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;

L'esecuzione su MySQL 5.5 offre:

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

Eseguendo questo su MySQL 5.6

0 row(s) affected   0.093 sec


2

Per mysql 5.7.21 uso quanto segue e funziona benissimo:

CREATE TABLE Posts( modified_attimestamp NON NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, created_attimestamp NON NULL DEFAULT CURRENT_TIMESTAMP)


1

penso che questa sia la query migliore per stamp_created e 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() 
); 

perché quando il record creato, stamp_createddeve essere compilato now()e stamp_updatedcompilato'0000-00-00 00:00:00'


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.