Pourquoi il ne peut y avoir qu'une seule colonne TIMESTAMP avec CURRENT_TIMESTAMP dans la clause DEFAULT?

180

Pourquoi il ne peut y avoir qu'une seule colonne TIMESTAMP avec CURRENT_TIMESTAMP dans la clause DEFAULT ou 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;

L'erreur qui en résulte:

Code d'erreur: 1293

Définition de table incorrecte; il ne peut y avoir qu'une seule colonne TIMESTAMP avec CURRENT_TIMESTAMP dans la clause DEFAULT ou ON UPDATE

ripper234
la source
6
C'est en fait bien pire que ce que le message d'erreur donne. Vous ne pouvez pas définir une colonne avec une clause CURRENT_TIMESTAMPin DEFAULTou ON UPDATEune fois qu'il y a une colonne avec TIMESTAMPun type de données, peu importe si elle a une clause supplémentaire!
Nicolas Buduroi
9
Donc ce travail 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 Pas si la première timestampcolonne est nullable ie null. Si la première timestampcolonne est not nullalors par défaut DEFAULT CURRENT_TIMESTAMPet ON UPDATE CURRENT_TIMESTAMPsera ajoutée. stackoverflow.com/a/13544181/2859238
user104309
@NicolasBuduroi Également pas si la première timestampcolonne a une valeur par défaut explicite définie comme default '0000-00-00 00:00:00'. Si la colonne est Nullable ou si la valeur par défaut est explicitement définie, alors DEFAULT CURRENT_TIMESTAMPet ON UPDATE CURRENT_TIMESTAMPne sera PAS ajoutée
user104309
Aimeriez-vous vraiment voir une réponse sur le pourquoi? pas comment le contourner ou comment il est résolu maintenant. Pourquoi cela a-t-il jamais été mis en œuvre de cette manière? Cela semble être une manière totalement braindead et je ne trouve aucune conception / implémentation qui pourrait être une raison de cette restriction. Je veux apprendre comment les gens stupides programment, alors s'il vous plaît, apprenez-moi.
Lothar

Réponses:

174

Cette limitation, qui était uniquement due à des raisons historiques d'héritage du code, a été levée dans les versions récentes de MySQL:

Changements dans MySQL 5.6.5 (10/04/2012, jalon 8)

Auparavant, au plus une colonne TIMESTAMP par table pouvait être automatiquement initialisée ou mise à jour à la date et à l'heure actuelles. Cette restriction a été levée. Toute définition de colonne TIMESTAMP peut avoir n'importe quelle combinaison de clauses DEFAULT CURRENT_TIMESTAMP et ON UPDATE CURRENT_TIMESTAMP. De plus, ces clauses peuvent désormais être utilisées avec les définitions de colonne DATETIME. Pour plus d'informations, consultez Initialisation et mise à jour automatiques pour TIMESTAMP et DATETIME.

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

augustin
la source
Vérifiez également la réponse @mooli ci-dessous. En fait, la première colonne d'horodatage a "default current_timestamp on update current_timestamp" automatiquement défini (il devrait donc être nommé updated_at). Il vous suffit de définir created_at manuellement au moment de l'insertion.
Gismo Ranas
que pouvons-nous faire si le vidage mysql appartient à une version 5.7 et que le programme d'installation doit être exécuté sur un 5.4
otc
1
@otc, vous pouvez modifier le vidage ou recommencer avec 5.4
Jasen
40

Je me suis également posé la question il y a longtemps. J'ai cherché un peu dans mon histoire et je pense que ce post: http://lists.mysql.com/internals/34919 représente la position semi-officielle de MySQL (avant l'intervention d'Oracle;))

En bref:

cette limitation découle uniquement de la manière dont cette fonctionnalité est actuellement implémentée dans le serveur et il n'y a pas d'autres raisons à son existence.

Leur explication est donc "parce que c'est implémenté comme ça". Cela ne semble pas très scientifique. Je suppose que tout vient d'un vieux code. Ceci est suggéré dans le fil ci-dessus: "report à partir du moment où seul le premier champ d'horodatage a été auto-défini / mis à jour".

À votre santé!

Lachezar Balev
la source
Wow, ça pue vraiment. J'espère que nous verrons bientôt un correctif.
BoltClock
47
Une autre grande limitation MySQL pour que nous puissions en profiter!
Nicolas Buduroi
1
@gorn, la solution / contournement la plus simple est celle de Scarlett ci-dessous.
Tihe
38

Nous pouvons donner une valeur par défaut pour l'horodatage pour éviter ce problème.

Cet article propose une solution de contournement détaillée: 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() 
);

Notez qu'il est nécessaire de saisir des valeurs nulles dans les deux colonnes lors de "l'insertion":

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
la source
16

En effet un défaut de mise en œuvre.

L'approche native de MySQL consiste à mettre à jour une date de création vous-même (si vous en avez besoin) et à faire en sorte que MySQL se soucie de l' horodatage update date ? update date : creation date comme ceci:

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

Lors de la création, insérer NULL:

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

Les valeurs NULL pour l'horodatage sont interpertées comme CURRENT_TIMESTAMP par défaut.

Dans MySQL, la première colonne TIMESTAMP d'une table obtient à la fois DEFAULT CURRENT_TIMESTAMPet ON UPDATE CURRENT_TIMESTAMPattribut, si aucun attribut n'est donné pour elle. c'est pourquoi la colonne TIMESTAMP avec les attributs doit venir en premier ou vous obtenez l'erreur décrite dans ce fil.

mooli
la source
14
  1. Changer les types de données des colonnes en datetime
  2. Définir le déclencheur

Tel que:

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
la source
J'ai toujours considéré cette méthode comme beaucoup moins insipide que la fonctionnalité CURRENT_TIMESTAMP à moitié implémentée.
TehShrike
1

Eh bien, un correctif pour vous pourrait être de le mettre dans le champ UpdatedDate et d'avoir un déclencheur qui met à jour le champ AddedDate avec la valeur UpdatedDate uniquement si AddedDate est nul.

HLGEM
la source
1

Combinaison de différentes réponses:

Dans MySQL 5.5, DEFAULT CURRENT_TIMESTAMPet ON UPDATE CURRENT_TIMESTAMPne peut pas être ajouté DATETIMEmais uniquement surTIMESTAMP .

Règles:

1) au plus une TIMESTAMPcolonne par table pourrait être automatiquement (ou manuellement [ Mon ajout ]) initialisée ou mise à jour à la date et à l'heure actuelles. (Documents MySQL).

Donc, un seul TIMESTAMPpeut avoir CURRENT_TIMESTAMPdans DEFAULTouON UPDATE clause

2) La première NOT NULL TIMESTAMPcolonne sans DEFAULTvaleur explicite comme created_date timestamp default '0000-00-00 00:00:00'sera implicitement donnée a DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPet donc les TIMESTAMPcolonnes suivantes ne peuvent pas être données CURRENT_TIMESTAMPsur la clause DEFAULTorON 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)

Autre option (mais updated_dateest la première colonne):

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
la source
0

Essaye ça:

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
la source
3
Cela fonctionnera mais ne résoudra pas le problème. created_at vaut 0, ce qui est en quelque sorte inutile.
CompEng88
@ ComputerEngineer88 C'est la bonne solution pour l'ancien serveur mysql. Vous devez définir la created_atcolonne vous-même. Je pense que c'est ce que op veut dire intentionnellement.
Roger
c'est exactement la solution officielle, documentée ici dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html
Rangi Lin
0

C'est la limitation de la version MYSQL 5.5. Vous devez mettre à jour la version à 5.6.

Error

J'obtenais cette erreur en ajoutant une table dans MYSQL

Définition de table incorrecte; il ne peut y avoir qu'une seule colonne TIMESTAMP avec CURRENT_TIMESTAMP dans la clause DEFAULT ou ON UPDATE Mon nouveau MYSQL

la table ressemble à quelque chose comme ça.

create table nom_table (col1 int (5) clé primaire auto_increment, col2 varchar (300), col3 varchar (500), col4 int (3), col5 tinyint (2), col6 timestamp par défaut current_timestamp, col7 timestamp par défaut current_timestamp lors de la mise à jour current_timestamp, col8 tinyint (1) par défaut 0, col9 tinyint (1) par défaut 1);

Après un certain temps de lecture sur les changements dans les différentes versions de MYSQL et une partie de la recherche sur Google. J'ai découvert que certaines modifications avaient été apportées à la version 5.6 de MYSQL par rapport à la version 5.5.

Cet article vous aidera à résoudre le problème. http://www.oyewiki.com/MYSQL/Incorrect-table-definition-there-can-be-only-one-timestamp-column

Ankur Rastogi
la source