¿Por qué solo puede haber una columna TIMESTAMP con CURRENT_TIMESTAMP en la cláusula DEFAULT?

180

¿Por qué solo puede haber una columna TIMESTAMP con CURRENT_TIMESTAMP en la cláusula DEFAULT o 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;

El error que resulta:

Código de error: 1293

Definición de tabla incorrecta; solo puede haber una columna TIMESTAMP con CURRENT_TIMESTAMP en la cláusula DEFAULT o ON UPDATE

ripper234
fuente
66
En realidad, es mucho peor de lo que el mensaje de error hace que parezca. ¡No puede definir una columna con CURRENT_TIMESTAMPin DEFAULTo ON UPDATEcláusula una vez que haya una columna con TIMESTAMPtipo de datos, sin importar si tiene una cláusula adicional!
Nicolas Buduroi
9
Entonces este trabajo: CREATE TABLE foo (created_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_on TIMESTAMP)pero no esto:CREATE TABLE foo (updated_on TIMESTAMP, created_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP)
Nicolas Buduroi
@NicolasBuduroi No si la primera timestampcolumna es anulable, es decir null. Si la primera timestampcolumna es not nullentonces por defecto DEFAULT CURRENT_TIMESTAMPy ON UPDATE CURRENT_TIMESTAMPse agregará. stackoverflow.com/a/13544181/2859238
user104309
@NicolasBuduroi Tampoco si la primera timestampcolumna tiene un valor predeterminado explícito establecido como default '0000-00-00 00:00:00'. Si la columna es anulable o explícitamente se establece el valor predeterminado, DEFAULT CURRENT_TIMESTAMPy ON UPDATE CURRENT_TIMESTAMPno se añadirá
user104309
Realmente me encantaría ver una respuesta sobre por qué? no cómo evitarlo o cómo se soluciona ahora. ¿Por qué se implementó esto de esta manera? Parece una manera totalmente mental y no puedo encontrar ningún diseño / implementación que pueda ser una razón para esta restricción. Quiero aprender cómo programa la gente tonta, así que por favor enséñame.
Lothar

Respuestas:

173

Esta limitación, que solo se debió a razones históricas de legado de código, se ha eliminado en versiones recientes de MySQL:

Cambios en MySQL 5.6.5 (2012-04-10, Milestone 8)

Anteriormente, como máximo una columna TIMESTAMP por tabla podía inicializarse o actualizarse automáticamente a la fecha y hora actuales. Esta restricción ha sido levantada. Cualquier definición de columna TIMESTAMP puede tener cualquier combinación de cláusulas DEFAULT CURRENT_TIMESTAMP y ON UPDATE CURRENT_TIMESTAMP. Además, estas cláusulas ahora se pueden usar con las definiciones de columna DATETIME. Para obtener más información, consulte Inicialización y actualización automáticas para TIMESTAMP y DATETIME.

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

augustin
fuente
Consulte también la respuesta de @mooli a continuación. En realidad, la primera columna de indicación de fecha y hora tiene "predeterminado current_timestamp en la actualización current_timestamp" automáticamente (por lo que debe llamarse updated_at). Solo tiene que configurar created_at manualmente en el momento de la inserción.
Gismo Ranas
¿Qué podemos hacer si el volcado mysql pertenece a una versión 5.7 y la configuración debe ejecutarse en un 5.4?
otc
1
@otc, puede editar el volcado o comenzar de nuevo con 5.4
Jasen
40

También me lo pregunté hace mucho tiempo. Busqué un poco en mi historia y creo que esta publicación: http://lists.mysql.com/internals/34919 representa la posición semioficial de MySQL (antes de la intervención de Oracle;))

En breve:

Esta limitación se debe únicamente a la forma en que esta característica se implementa actualmente en el servidor y no hay otras razones para su existencia.

Entonces su explicación es "porque se implementa así". No suena muy científico. Supongo que todo proviene de un código antiguo. Esto se sugiere en el hilo anterior: "transferencia de cuando solo el primer campo de marca de tiempo se configuró / actualizó automáticamente".

¡Salud!

Lachezar Balev
fuente
Wow, eso realmente apesta. Espero que veamos una solución pronto.
BoltClock
46
¡Otra gran limitación de MySQL para que disfrutemos!
Nicolas Buduroi
1
@gorn la solución / solución más fácil es la de Scarlett a continuación.
Tihe
38

Podemos dar un valor predeterminado para la marca de tiempo para evitar este problema.

Esta publicación ofrece una solución detallada: 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() 
);

Tenga en cuenta que es necesario ingresar valores nulos en ambas columnas durante la "inserción":

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

De hecho, un error de implementación.

El enfoque nativo en MySQL es actualizar una fecha de creación usted mismo (si lo necesita) y hacer que MySQL se preocupe por la marca de tiempo de esta update date ? update date : creation date manera:

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

En la creación Insertar NULL:

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

Los valores NULL para la marca de tiempo se interpelan como CURRENT_TIMESTAMP de forma predeterminada.

En MySQL, la primera columna TIMESTAMP de una tabla obtiene ambos DEFAULT CURRENT_TIMESTAMPy un ON UPDATE CURRENT_TIMESTAMPatributo, si no se le dan atributos. esta es la razón por la cual la columna TIMESTAMP con atributos debe ser lo primero u obtener el error descrito en este hilo.

mooli
fuente
14
  1. Cambiar los tipos de datos de columnas a fecha y hora
  2. Establecer disparador

Como:

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 ;
Ting Feng-Chun
fuente
Siempre he considerado este método mucho menos desagradable que la funcionalidad CURRENT_TIMESTAMP medio implementada.
TehShrike
1

Bueno, una solución para usted podría ser ponerlo en el campo UpdatedDate y tener un activador que actualice el campo AddedDate con el valor UpdatedDate solo si AddedDate es nulo.

HLGEM
fuente
1

Combinando varias respuestas:

En MySQL 5.5, DEFAULT CURRENT_TIMESTAMPy ON UPDATE CURRENT_TIMESTAMPno se puede agregar DATETIMEsino solo en TIMESTAMP.

Reglas:

1) como máximo una TIMESTAMPcolumna por tabla podría inicializarse o actualizarse automáticamente (o manualmente [ Mi adición ]) a la fecha y hora actuales. (Documentos de MySQL).

Por lo que sólo uno TIMESTAMPpuede tener CURRENT_TIMESTAMPen DEFAULTo ON UPDATEcláusula

2) La primera NOT NULL TIMESTAMPcolumna sin una explícita DEFAULTvalor como created_date timestamp default '0000-00-00 00:00:00'será implícitamente dan una DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPy por lo tanto posteriores TIMESTAMPcolumnas no se pueden dar CURRENT_TIMESTAMPen DEFAULTo ON UPDATEcláusula

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)

Otra opción (pero updated_datees la primera columna):

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;
usuario104309
fuente
0

Prueba esto:

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
fuente
3
Esto funcionará pero no resuelve el problema. created_at es 0, que es un poco inútil.
CompEng88
@ ComputerEngineer88 Esta es la solución correcta para el antiguo servidor mysql. Debe configurar la created_atcolumna usted mismo. Creo que esto es lo que op quiere decir intencionalmente.
Roger
esta es exactamente la solución oficial, documentada aquí dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html
Rangi Lin
0

Esta es la limitación en la versión MYSQL 5.5. Necesita actualizar la versión a 5.6.

Error

Recibía este error al agregar una tabla en MYSQL

Definición de tabla incorrecta; solo puede haber una columna TIMESTAMP con CURRENT_TIMESTAMP en DEFAULT o en la cláusula ON UPDATE Mi nuevo MYSQL

La mesa se parece a esto.

crear tabla nombre_tabla (col1 int (5) auto_increment clave principal, col2 varchar (300), col3 varchar (500), col4 int (3), col5 tinyint (2), col6 timestamp default current_timestamp, col7 timestamp default current_timestamp en actualizar current_timestamp, col8 tinyint (1) predeterminado 0, col9 tinyint (1) predeterminado 1);

Después de un tiempo de lectura sobre los cambios en diferentes versiones de MYSQL y algunas de las búsquedas en Google. Descubrí que se hicieron algunos cambios en MYSQL versión 5.6 sobre la versión 5.5.

Este artículo te ayudará a resolver el problema. http://www.oyewiki.com/MYSQL/Incorrect-table-definition-there-can-be-only-one-timestamp-column

Ankur Rastogi
fuente