Por que pode haver apenas uma coluna TIMESTAMP com CURRENT_TIMESTAMP na cláusula DEFAULT?

180

Por que pode haver apenas uma coluna TIMESTAMP com CURRENT_TIMESTAMP na cláusula 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;

O erro que resulta:

Código de erro: 1293

Definição de tabela incorreta; pode haver apenas uma coluna TIMESTAMP com CURRENT_TIMESTAMP na cláusula DEFAULT ou ON UPDATE

ripper234
fonte
6
Na verdade, é muito pior do que a mensagem de erro faz parecer. Você não pode definir uma coluna com CURRENT_TIMESTAMPin DEFAULTou ON UPDATEcláusula uma vez que exista uma coluna com TIMESTAMPtipo de dados, independentemente de ter uma cláusula extra!
Nicolas Buduroi
9
Portanto, este trabalho 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 Não se a primeira timestampcoluna for anulável, ou seja null. Se a primeira timestampcoluna for not null, por padrão, DEFAULT CURRENT_TIMESTAMPe ON UPDATE CURRENT_TIMESTAMPserá adicionada. stackoverflow.com/a/13544181/2859238 #
user104309
@NicolasBuduroi Também não se a primeira timestampcoluna tiver um valor padrão explícito definido como default '0000-00-00 00:00:00'. Se a coluna for anulável ou se o valor padrão explicitamente for definido, DEFAULT CURRENT_TIMESTAMPe ON UPDATE CURRENT_TIMESTAMPNÃO será adicionado #
user104309 17/17/17/17
Realmente adoraria ver uma resposta sobre o porquê? não como contornar ou como está consertado agora. Por que isso foi implementado dessa maneira? Parece uma maneira totalmente desafiadora e não consigo encontrar nenhum design / implementação que possa ser um motivo para essa restrição. Eu quero aprender como as pessoas burras programam, então por favor me ensine.
Lothar

Respostas:

173

Essa limitação, devido apenas a razões históricas de legado de código, foi levantada nas versões recentes do MySQL:

Alterações no MySQL 5.6.5 (10-04-2012, marco 8)

Anteriormente, no máximo uma coluna TIMESTAMP por tabela podia ser inicializada ou atualizada automaticamente para a data e hora atuais. Esta restrição foi levantada. Qualquer definição de coluna TIMESTAMP pode ter qualquer combinação das cláusulas DEFAULT CURRENT_TIMESTAMP e ON UPDATE CURRENT_TIMESTAMP. Além disso, essas cláusulas agora podem ser usadas com definições de coluna DATETIME. Para obter mais informações, consulte Inicialização e atualização automáticas para TIMESTAMP e DATETIME.

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

agosto
fonte
Veja também a resposta @mooli abaixo. Na verdade, a primeira coluna de registro de data e hora tem "default_timestamp padrão na atualização current_timestamp" definido automaticamente (portanto, deve ser nomeado updated_at). Você só precisa definir o created_at manualmente no momento da inserção.
Gismo Ranas
o que podemos fazer se o dump do mysql pertencer a uma versão 5.7 e a instalação precisar ser executada em um 5.4
otc
1
@otc, você pode editar o despejo, ou começar de novo com 5,4
Jasen
40

Eu também me perguntei isso há muito tempo. Pesquisei um pouco na minha história e acho que este post: http://lists.mysql.com/internals/34919 representa a posição semioficial do MySQL (antes da intervenção da Oracle;))

Em resumo:

essa limitação decorre apenas da maneira como esse recurso está implementado no servidor e não há outros motivos para sua existência.

Portanto, a explicação deles é "porque é implementada assim". Não parece muito científico. Eu acho que tudo vem de algum código antigo. Isso é sugerido no encadeamento acima: "transferência a partir de quando apenas o primeiro campo de registro de data e hora foi definido automaticamente / atualizado".

Felicidades!

Lachezar Balev
fonte
Uau, isso realmente fede. Espero que possamos ver uma correção em breve.
BoltClock
46
Outra grande limitação do MySQL para nós aproveitarmos!
Nicolas Buduroi 14/01
1
@gorn a solução mais fácil / solução alternativa é a de Scarlett abaixo.
2013
38

Podemos fornecer um valor padrão para o carimbo de data / hora para evitar esse problema.

Esta postagem fornece uma solução detalhada: 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() 
);

Observe que é necessário inserir nulos nas duas colunas durante a "inserção":

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

De fato, uma falha de implementação.

A abordagem nativa no MySQL é atualizar você mesmo uma data de criação (se você precisar de uma) e fazer com que o MySQL se preocupe com o timestamp da seguinte update date ? update date : creation date maneira:

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

Na criação, insira NULL:

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

Os valores NULL para o registro de data e hora são interferidos como CURRENT_TIMESTAMP por padrão.

No MySQL, a primeira coluna TIMESTAMP de uma tabela obtém ambos DEFAULT CURRENT_TIMESTAMPe ON UPDATE CURRENT_TIMESTAMPatributo, se nenhum atributo for fornecido para ela. é por isso que a coluna TIMESTAMP com atributos deve vir primeiro ou você obtém o erro descrito neste encadeamento.

mooli
fonte
14
  1. Alterar tipos de dados de colunas para data e hora
  2. Definir gatilho

Tal 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 ;
Feng-Chun Ting
fonte
Sempre considerei esse método muito menos irreverente do que a funcionalidade CURRENT_TIMESTAMP semi-implementada.
TehShrike
1

Bem, uma correção para você pode ser colocá-lo no campo UpdatedDate e ter um gatilho que atualize o campo AddedDate com o valor UpdatedDate apenas se AddedDate for nulo.

HLGEM
fonte
1

Combinando várias respostas:

No MySQL 5.5, DEFAULT CURRENT_TIMESTAMPe ON UPDATE CURRENT_TIMESTAMPnão pode ser adicionado, DATETIMEmas apenas ativado TIMESTAMP.

Regras:

1) no máximo uma TIMESTAMPcoluna por tabela pode ser automaticamente (ou manualmente [ Minha adição ]) inicializada ou atualizada para a data e hora atuais. (Documentos do MySQL).

Assim, apenas um TIMESTAMPpode ter CURRENT_TIMESTAMPem DEFAULTou ON UPDATEcláusula

2) A primeira NOT NULL TIMESTAMPcoluna sem um DEFAULTvalor explícito como created_date timestamp default '0000-00-00 00:00:00'receberá implicitamente uma DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPe, portanto, as TIMESTAMPcolunas subsequentes não poderão ser fornecidas nem CURRENT_TIMESTAMPna cláusulaDEFAULTON 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)

Outra opção (mas updated_dateé a primeira coluna):

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
fonte
0

Tente o seguinte:

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
fonte
3
Isso vai funcionar, mas não resolve o problema. created_at é 0, o que é meio inútil.
CompEng88
@ ComputerEngineer88 Esta é a solução certa para o servidor mysql antigo. Você deve definir a created_atcoluna você mesmo. Eu acho que é isso que op quer dizer intencionalmente.
Roger
este é exatamente a solução oficial, documentado aqui dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html
Rangi Lin
0

Essa é a limitação na versão do MYSQL 5.5. Você precisa atualizar a versão para 5.6.

Error

Eu estava recebendo esse erro ao adicionar uma tabela no MYSQL

Definição de tabela incorreta; pode haver apenas uma coluna TIMESTAMP com CURRENT_TIMESTAMP na cláusula DEFAULT ou ON UPDATE My new MYSQL

tabela se parece com isso.

criar tabela nome_tabela (col1 int (5) chave primária auto_increment, col2 varchar (300), col3 varchar (500), col4 int (3), col5 tinyint (2), col6 timestamp default current_timestamp, col7 timestamp default current_timestamp na atualização current_timestamp, col8 tinyint (1) padrão 0, col9 tinyint (1) padrão 1);

Depois de algum tempo lendo sobre mudanças em diferentes versões do MYSQL e alguns dos googling. Descobri que algumas alterações foram feitas no MYSQL versão 5.6 sobre versão 5.5.

Este artigo ajudará você a resolver o problema. http://www.oyewiki.com/MYSQL/Incorrect-table-definition-there-can-be-only-one-timestamp-column

Ankur Rastogi
fonte