Tendo colunas de carimbo de data e hora criadas e da última atualização no MySQL 4.0

127

Eu tenho o seguinte esquema de tabela;

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;

Falha com o seguinte erro:

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

Minha pergunta é: posso ter os dois campos? ou preciso definir manualmente um campo LastUpdated durante cada transação?

Xenph Yan
fonte
@Xenph Yan, você se importaria de alterar a resposta "Aceita" da atual incorreta para a correta? Esta resposta aceita, errada me fez perder cerca de 15 minutos tentando descobrir o que estava acontecendo ...
de Bruno Reis
1
@BrunoReis Concluído, obrigado pela coleta.
Xenph Yan

Respostas:

128

Na documentação do MySQL 5.5 :

Uma coluna TIMESTAMP em uma tabela pode ter o registro de data e hora atual como o valor padrão para inicializar a coluna, como o valor de atualização automática ou ambos. Não é possível que o registro de data e hora atual seja o valor padrão para uma coluna e o valor de atualização automática para outra coluna.

Alterações no MySQL 5.6.5 :

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.

Robert Gamble
fonte
Isso mudou (pelo menos no MySQL 5.0). Consulte a documentação: dev.mysql.com/doc/refman/5.0/en/timestamp.html
SimonSimCity
Combatendo @SimonSimCity: Os documentos para 5.0 dizem exatamente a mesma coisa que acima.
Davemyron em 04/04
5
@RobertGamble Acho que a pergunta mais interessante seria: POR QUE O PESCOÇO NÃO FORNECEU uma maneira de fazer essa funcionalidade muito solicitada / necessária.
Ray
22
Isso parece um pouco arbitrário por parte do MySQL. Alguém pode explicar por que esse é o caso?
Humble_coder 22/08/2012
12
Comentário muito antigo, mas finalmente foi alterado: 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

Existe um truque para ter os dois registros de data e hora, mas com um pouco de limitação.

Você pode usar apenas uma das definições em uma tabela. Crie as duas colunas de carimbo de data e hora da seguinte forma:

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 entrar nullnas duas colunas 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)  
Bogdan Gusiev
fonte
Aqui está um link da documentação do MySQL que descreve essa função: dev.mysql.com/doc/refman/5.0/en/timestamp.html
SimonSimCity
6
a primeira caixa de código, quando inserida manualmente, funcionou perfeitamente para mim. Obrigado! Eu gostaria de ter 'carma' suficiente para aprovar esta resposta, pois salvou meu bacon. mmmmm economizou bacon.
amatusko
Você precisa ter certeza de que stamp_created também está definido como NOT NULL. O MySQL substituirá automaticamente o NULL pelo registro de data e hora atual.
Valentin Despa
Por que você também não cria o stamp_createdcampo como: em stamp_created timestamp default now()vez de usar um valor 'ZERO'?
Sebastian Scholle
28

Você pode ter os dois, basta retirar o sinalizador "CURRENT_TIMESTAMP" no campo criado. Sempre que você criar um novo registro na tabela, use "NOW ()" para um valor.

Ou.

Pelo contrário, remova o sinalizador 'ON UPDATE CURRENT_TIMESTAMP' e envie o NOW () para esse campo. Dessa forma, na verdade, faz mais sentido.

Stephen Walcher
fonte
2
É este o único caminho? Não posso fazer com que o banco de dados cuide de todos esses detalhes?
Xenph Yan 6/11
2
De acordo com o manual do MySql, CURRENT_TIMESTAMP é sinônimo de NOW (), então não acho que isso funcione.
tvanfosson 6/11/08
Tenho certeza que você pode, é que CURRENT_TIMESTAMP é um sinalizador reservado para apenas um campo. De qualquer forma, se você tivesse esse sinalizador lá, independentemente do valor que você tem para esse campo ao adicionar um registro, sempre será o carimbo de data / hora atual, daí o nome.
Stephen Walcher
1
@tvanfosson: Usar 'NOW ()' em uma consulta passa o horário atual para o banco de dados. Qual é realmente esse valor depende do idioma, mecanismo e provavelmente centenas de outras coisas que eu não sei. O sinalizador ao qual eu estava me referindo o define para que, quando um registro for criado, a hora seja adicionada a esse campo.
Stephen Walcher
2
Eu segui a maneira de inserir NOW (), principalmente porque outro código pode tocar nessas tabelas e não confio nas pessoas para atualizá-las corretamente. :)
Xenph Yan 6/11/08
26

Se você decidir que o MySQL lide com a atualização dos registros de data e hora, poderá configurar um gatilho para atualizar o campo ao inserir.

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

Referência do MySQL: http://dev.mysql.com/doc/refman/5.0/en/triggers.html

webkraller
fonte
Bom, era isso que eu estava procurando. Não quero depender de pessoas adicionadas NOW () na consulta!
Bot
na verdade, seria melhor fazer depois de inserção, e definir novas <timestamp_field> = new <timestamp_field que realmente tem que ter o current_timestamp default> Desta forma ambos os campos são consistente..
KacieHouser
@KacieHouser A atualização da nova linha não é permitida após o acionamento #
Thomas
23

É assim que você pode ter campos createDate / lastModified automáticos e flexíveis usando gatilhos:

Primeiro, defina-os assim:

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

Em seguida, adicione estes gatilhos:

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 você inserir sem especificar createDate ou lastModified, eles serão iguais e configurados para o carimbo de data / hora atual.
  • Se você atualizá- los sem especificar createDate ou lastModified, lastModified será definido como o carimbo de data / hora atual.

Mas aqui está a parte legal:

  • Se você inserir , poderá especificar um createDate mais antigo que o registro de data e hora atual , permitindo que as importações de tempos antigos funcionem bem (lastModified será igual a createDate).
  • Se você atualizar , poderá especificar um lastModified mais antigo que o valor anterior ('0000-00-00 00:00:00' funciona bem), permitindo atualizar uma entrada se você estiver fazendo alterações cosméticas (corrigindo um erro de digitação em um comentário ) e você deseja manter a data lastModified antiga . Isso não modificará a data lastModified.
estrangeiro
fonte
21

No MySQL 5.6, é fácil de usar ... tente:

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
fonte
Provavelmente grande solução que eu estou procurando criar e atualização questão do tempo sem gatilho
matinict
Não acredito que demorou tanto tempo para que esse pequeno incômodo fosse resolvido. Eu nem sabia que eles tinham consertado isso e é 2018 ... Obrigado.
hsanders
4

Esse problema parecia ter sido resolvido no MySQL 5.6. Eu notei isso até o MySQL 5.5; aqui está um código de exemplo:

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;

A execução no MySQL 5.5 fornece:

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

Executando isso no MySQL 5.6

0 row(s) affected   0.093 sec
Kingz
fonte
2

Para o mysql 5.7.21, uso o seguinte e funciona bem:

CREATE TABLE Posts( modified_atregistro de data e hora NOT NULL DEFAULT CURRENT_TIMESTAMP EM ATUALIZAÇÃO CURRENT_TIMESTAMP, created_atregistro de data e hora NOT NULL DEFAULT CURRENT_TIMESTAMP)

Ioannis Chrysochos
fonte
1

Eu acho que esta é a melhor consulta para 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() 
); 

porque quando o registro criado, stamp_createddeve ser preenchido por now()e stamp_updateddeve ser preenchido por'0000-00-00 00:00:00'

Anonim-
fonte