Come posso impostare il valore predefinito di una colonna timestamp sul timestamp corrente con le migrazioni Laravel?


168

Vorrei creare una colonna timestamp con un valore predefinito di CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPutilizzo di Laravel Schema Builder / Migrations. Ho esaminato più volte la documentazione di Laravel e non vedo come posso impostarlo come predefinito per una colonna timestamp.

La timestamps()funzione effettua i valori predefiniti 0000-00-00 00:00per entrambe le colonne che crea.

Risposte:


310

Dato che è un'espressione cruda, è necessario utilizzare DB::raw()per set CURRENT_TIMESTAMPcome un valore predefinito per una colonna:

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

Funziona perfettamente su ogni driver di database.

Nuova scorciatoia

A partire da Laravel 5.1.25 (vedere PR 10962 e commit 15c487fe ) è possibile utilizzare il nuovo useCurrent()metodo modificatore di colonna per impostare il CURRENT_TIMESTAMPvalore predefinito per una colonna:

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

Tornando alla domanda, su MySQL puoi anche usare la ON UPDATEclausola attraverso DB::raw():

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

Trabocchetti

  • MySQL

    A partire da MySQL 5.7, 0000-00-00 00:00:00non è più considerata una data valida. Come documentato nella guida all'aggiornamento di Laravel 5.2 , tutte le colonne del timestamp dovrebbero ricevere un valore predefinito valido quando si inseriscono i record nel database. È possibile utilizzare il useCurrent()modificatore di colonna (da Laravel 5.1.25 e versioni successive) nelle migrazioni per impostare automaticamente le colonne del timestamp sui timestamp correnti oppure è possibile creare i timestamp nullable()per consentire valori null.

  • PostgreSQL e Laravel 4.x

    Nelle versioni Laravel 4.x, il driver PostgreSQL utilizzava la precisione del database predefinita per memorizzare i valori di data e ora. Quando si utilizza la CURRENT_TIMESTAMPfunzione su una colonna con una precisione predefinita, PostgreSQL genera un timestamp con la maggiore precisione disponibile, generando così un timestamp con una seconda parte frazionaria - vedere questo violino SQL .

    Questo porterà Carbon a fallire nell'analisi di un timestamp poiché non si aspetta che i microsecondi vengano memorizzati. Per evitare che questo comportamento imprevisto rompa l'applicazione, è necessario fornire esplicitamente una precisione zero alla CURRENT_TIMESTAMPfunzione come di seguito:

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

    Da Laravel 5.0, le timestamp()colonne sono state modificate per utilizzare una precisione predefinita pari a zero che evita ciò.

    Grazie a @andrewhl per aver segnalato questo problema nei commenti.


Suggerimento migliore quindi il mio. Usa questo invece del mio DB::statementesempio, questo è molto più semplice.
Marwelln,

Questo può essere usato anche per le dichiarazioni PARTITION BY nei tuoi test?
Glenn Plas,

2
Non in modo impeccabile. Per PostgreSQL 'CURRENT_TIMESTAMP' restituisce qualcosa nel formato: 2014-08-11 15: 06: 29.692439. Ciò causa il fallimento del metodo Carbon :: createFromFormat ('Ymd H: i: s', $ timestamp) (non può analizzare i millisecondi finali). Questo è usato da Laravel quando accede ai timestamp. Per risolvere PostgreSQL, utilizzare: DB :: raw ('now () :: timestamp (0)') (riferimento: postgresql.org/docs/8.1/static/… )
andrewhl,

@andrewhl In realtà ho risposto solo per MySQL, poiché è l'oggetto della domanda. Ma grazie per averlo condiviso con noi, aggiornerò la mia risposta per coprirlo! :)
Paulo Freitas,

55

Per creare entrambe le colonne 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'));

Avrai bisogno della versione di MySQL> = 5.6.5 per avere più colonne con CURRENT_TIMESTAMP


3
Perché non usare solo $table->timestamps()->default(DB::raw('CURRENT_TIMESTAMP'));?
Dave,

1
@dave Perché allora updated_atnon cambierebbe quando il record è stato modificato dopo la sua creazione iniziale
Erik Berkun-Drevnig

Sì, aggiungi a che i timestamp () non consentono comunque le impostazioni predefinite, quindi non funzionerebbe affatto. Avevo impegnato il codice per consentirlo, ma i gestori di Laravel non vogliono davvero che le persone utilizzino il valore predefinito nel modo in cui lo stiamo utilizzando (supponendo perché le versioni di MySQL precedenti alla 5.6.5 non consentono più colonne con timestamp come predefinito).
Dave,

In realtà update_at è gestito da Eloquent, quindi non è necessario il bit "on update" poiché verrà impostato quando un modello viene aggiornato automaticamente.
Dmyers,

@dmyers Se stai usando eloquent, puoi semplicemente farlo, $t->timestamps();ma questo non risponde alla domanda.
Brian Adams,

44

A partire da Laravel 5.1.26, taggato il 02-12-2015, useCurrent()è stato aggiunto un modificatore:

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

PR 10962 (seguito da commit 15c487fe ) ha portato a questa aggiunta.

Puoi anche leggere i numeri 3602 e 11518 che sono di interesse.

Fondamentalmente, MySQL 5.7 (con la configurazione predefinita) richiede di definire un valore predefinito o nullable per i campi temporali.


10

Questo non funziona per certo:

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

Non rimuove lo "0 predefinito" che sembra derivare dalla selezione del timestamp e aggiunge semplicemente il valore predefinito personalizzato. Ma ne abbiamo bisogno senza le virgolette. Non tutto ciò che manipola un DB proviene da Laravel4. Questo è il suo punto. Vuole impostazioni predefinite personalizzate su determinate colonne come:

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

Non credo sia possibile con Laravel. Sto cercando un'ora da ora per vedere se è possibile.


Aggiornamento: la risposta di Paulos Freita mostra che è possibile, ma la sintassi non è semplice.


Grande. Roba perfetta Complimenti, anche questo mi ha aiutato.
Glenn Plas,

piccola osservazione, prima di urlare: questo non funziona per me in laravel, date un'occhiata alla data in cui questa risposta è stata scritta: 2013. All'epoca era valida. Lo apprezzerei prima di toccare la freccia giù.
Glenn Plas,

9

Come possibilità aggiuntiva per futuri googler

Trovo più utile avere null nella colonna updated_at quando il record è stato creato ma non è mai stato modificato . Riduce la dimensione del db (ok, solo un po ') ed è possibile vederlo a prima vista che i dati non sono mai stati modificati.

A partire da questo utilizzo:

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

(In Laravel 7 con mysql 8).


7

Usa invece il suggerimento di Paulo Freitas .


Fino a quando Laravel non risolve questo problema, è possibile eseguire una query standard del database dopo l' Schema::createesecuzione.

    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");

Ha funzionato a meraviglia per me.


È un bel trucco. Vorrei che il generatore di schemi supportasse le tabelle partizionate mentre le uso ovunque. Ho provato a scavare nel codice ma per me non è ovvio dove modificarlo.
Glenn Plas,

-2

Ecco come lo fai, l'ho verificato e funziona sul mio Laravel 4.2.

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

Spero che questo ti aiuti.


-5

In Laravel 5 semplicemente:

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

Documentazione: http://laravel.com/docs/5.1/migrations#creating-columns


13
Ma ciò non imposta il valore predefinito su CURRENT_TIMESTAMP come richiesto nella domanda.
Josh,

provo questo, ma dato null in 5.4 idk perché, ma quando provo -> useCurrent (); funziona benissimo
Anthony Kal,

non risponde alla domanda di CURRENT_TIMESTAMPsu created_atcolonna e on UPDATE CURRENT_TIMESTAMPsu updated_atcolonna. Fino a quando la gente di Laravel non lo risolverà, usa questo: $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP')); $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
Hamza Rashid,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.