Como definir o valor padrão de uma coluna de carimbo de data / hora como o carimbo de data / hora atual com migrações do Laravel?

167

Gostaria de criar uma coluna de carimbo de data / hora com um valor padrão do CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPuso do Laravel Schema Builder / Migrations. Examinei a documentação do Laravel várias vezes e não vejo como posso tornar isso o padrão para uma coluna de carimbo de data / hora.

o timestamps() função faz os padrões 0000-00-00 00:00para as duas colunas que faz.

JoeyD473
fonte

Respostas:

310

Como é uma expressão bruta, você deve DB::raw()definir CURRENT_TIMESTAMPcomo valor padrão para uma coluna:

$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));

Isso funciona perfeitamente em todos os drivers de banco de dados.

Novo atalho

No Laravel 5.1.25 (consulte PR 10962 e commit 15c487fe ), você pode usar o novo useCurrent()método de modificação de colunas para definir o CURRENT_TIMESTAMPvalor padrão para uma coluna:

$table->timestamp('created_at')->useCurrent();

De volta à pergunta, no MySQL você também pode usar a ON UPDATEcláusula através de DB::raw():

$table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));

Pegadinhas

  • MySQL

    A partir do MySQL 5.7, 0000-00-00 00:00:00não é mais considerada uma data válida. Conforme documentado no guia de atualização do Laravel 5.2 , todas as colunas de carimbo de data / hora devem receber um valor padrão válido quando você insere registros no seu banco de dados. Você pode usar o useCurrent()modificador de coluna (do Laravel 5.1.25 e posterior) em suas migrações para padronizar as colunas de carimbo de data / hora para os carimbos de hora atuais ou pode fazer os carimbos nullable()de hora para permitir valores nulos.

  • PostgreSQL e Laravel 4.x

    Nas versões do Laravel 4.x, o driver do PostgreSQL usava a precisão padrão do banco de dados para armazenar valores de carimbo de data / hora. Ao usar a CURRENT_TIMESTAMPfunção em uma coluna com uma precisão padrão, o PostgreSQL gera um registro de data e hora com a maior precisão disponível, gerando um registro de data e hora com uma segunda parte fracionária - veja este violino SQL .

    Isso levará o Carbon a falhar na análise de um carimbo de data / hora, uma vez que não estará esperando microssegundos sendo armazenados. Para evitar esse comportamento inesperado que interrompe seu aplicativo, você precisa explicitamente dar uma precisão zero à CURRENT_TIMESTAMPfunção, conforme abaixo:

    $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP(0)'));

    Desde o Laravel 5.0, as timestamp()colunas foram alteradas para usar uma precisão padrão zero, o que evita isso.

    Agradecemos a @andrewhl por apontar esse problema nos comentários.

Paulo Freitas
fonte
Muito melhor sugestão do que a minha. Use isso em vez do meu DB::statementexemplo, isso é muito mais simples.
Marwelln
Isso também pode ser usado para instruções PARTITION BY em seus testes?
Glenn Plas
2
Não perfeitamente. Para o PostgreSQL, 'CURRENT_TIMESTAMP' retorna algo no formato de: 2014-08-11 15: 06: 29.692439. Isso faz com que o método Carbon :: createFromFormat ('Ymd H: i: s', $ timestamp) falhe (ele não pode analisar os milissegundos finais). Isso é usado pelo Laravel ao acessar registros de data e hora. Para corrigir o PostgreSQL, use: DB :: raw ('now () :: timestamp (0)') (referência: postgresql.org/docs/8.1/static/… )
andrewhl
@andrewhl Na verdade, eu respondi apenas pelo MySQL, já que é o assunto da pergunta. Mas obrigado por compartilhar isso conosco, vou atualizar minha resposta para cobrir isso! :)
Paulo Freitas
55

Para criar as colunas created_ate updated_at:

$t->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
$t->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));

Você precisará da versão MySQL> = 5.6.5 para ter várias colunas com CURRENT_TIMESTAMP

Brian Adams
fonte
3
Por que não usar apenas $table->timestamps()->default(DB::raw('CURRENT_TIMESTAMP'));?
dave
1
@ Dave Porque então updated_atnão mudaria quando o registro foi modificado após sua criação inicial
Erik Berkun-Drevnig
Sim, adicione a isso que os carimbos de data / hora () não permitem padrões de qualquer maneira, portanto não funcionariam. Eu havia comprometido o código para permitir isso, mas os gerentes do Laravel realmente não querem que as pessoas usem o padrão da maneira como o usamos (supondo que as versões do MySQL anteriores à 5.6.5 não permitam várias colunas com timestamps como padrão).
dave
Na verdade, o updated_at é gerenciado pela Eloquent, portanto, não há necessidade do bit "em atualização", pois ele será definido quando um modelo for atualizado automaticamente.
Dmyers 28/04
@ dmyers Se você estiver usando eloquente, pode fazer, $t->timestamps();mas isso não responde à pergunta.
Brian Adams
44

A partir do Laravel 5.1.26, marcado com 02/12/2015, um useCurrent()modificador foi adicionado:

Schema::table('users', function ($table) {
    $table->timestamp('created')->useCurrent();
});

O PR 10962 (seguido pelo commit 15c487fe ) levou a essa adição.

Você também pode ler os problemas 3602 e 11518 que são de interesse.

Basicamente, o MySQL 5.7 (com configuração padrão) requer que você defina um valor padrão ou anulável para os campos de tempo.

Gras Double
fonte
10

Isso não funciona de fato:

$table->timestamp('created_at')->default('CURRENT_TIMESTAMP');

Ele não remove o 'padrão 0' que parece vir com a seleção do carimbo de data e hora e apenas acrescenta o padrão personalizado. Mas meio que precisamos disso sem as aspas. Nem tudo o que manipula um banco de dados vem do Laravel4. Esse é o ponto dele. Ele deseja padrões personalizados em determinadas colunas, como:

$table->timestamps()->default('CURRENT_TIMESTAMP');

Não acho que seja possível com o Laravel. Estou procurando há uma hora agora para ver se é possível.


Atualização: A resposta de Paulos Freita mostra que é possível, mas a sintaxe não é direta.

Glenn Plas
fonte
Ótimo. Coisas perfeitas. Polegares para cima, isso me ajudou também.
Glenn Plas
pequena observação, antes de gritar: isso não funciona para mim no laravel, dê uma olhada na data em que esta resposta foi escrita: 2013. Era válida na época. Eu agradeceria antes de tocar na seta para baixo.
Glenn Plas
9

Como possibilidade adicional para futuros googlers

Acho mais útil ter nulo na coluna updated_at quando o registro é criado, mas nunca foi modificado . Reduz o tamanho do banco de dados (ok, apenas um pouco) e é possível vê-lo à primeira vista que os dados nunca foram modificados.

A partir disso, eu uso:

$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->default(DB::raw('NULL ON UPDATE CURRENT_TIMESTAMP'))->nullable();

(No Laravel 7 com o mysql 8).

ndberg
fonte
7

Use a sugestão de Paulo Freitas .


Até o Laravel corrigir isso, você pode executar uma consulta padrão ao banco de dados após a Schema::createexecução.

    Schema::create("users", function($table){
        $table->increments('id');
        $table->string('email', 255);
        $table->string('given_name', 100);
        $table->string('family_name', 100);
        $table->timestamp('joined');
        $table->enum('gender', ['male', 'female', 'unisex'])->default('unisex');
        $table->string('timezone', 30)->default('UTC');
        $table->text('about');
    });
    DB::statement("ALTER TABLE ".DB::getTablePrefix()."users CHANGE joined joined TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL");

Isso funcionou maravilhosamente para mim.

Marwelln
fonte
Esse é um bom truque. Desejo que o construtor de esquemas suporte tabelas particionadas à medida que as uso em todo o lugar. Eu tentei cavar o código, mas não é tão óbvio para mim onde modificar isso.
Glenn Plas
-2

É assim que você faz, eu verifiquei e funciona no meu Laravel 4.2.

$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));

Espero que isto ajude.

Jawad
fonte
-4

No Laravel 5, basta:

$table->timestamps(); //Adds created_at and updated_at columns.

Documentação: http://laravel.com/docs/5.1/migrations#creating-columns

JoenMarz
fonte
12
Mas isso não define o padrão como CURRENT_TIMESTAMP, conforme solicitado na pergunta.
21716 Josh
Eu tento isso, mas dado nulo em 5,4 idk por que, mas quando eu tento -> useCurrent (); sua multa trabalho
Anthony Kal
não responde à pergunta CURRENT_TIMESTAMPna created_atcoluna e on UPDATE CURRENT_TIMESTAMPna updated_atcoluna. Até que o pessoal do Laravel conserte, use o seguinte: $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP')); $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
Hamza Rashid