Wie kann ich den Standardwert einer Zeitstempelspalte mit Laravel-Migrationen auf den aktuellen Zeitstempel setzen?

166

Ich möchte eine Zeitstempelspalte mit dem Standardwert " CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPLaravel Schema Builder / Migrations" erstellen. Ich habe die Laravel-Dokumentation mehrmals durchgesehen und sehe nicht, wie ich dies als Standard für eine Zeitstempelspalte festlegen kann.

Die timestamps()Funktion legt die Standardeinstellungen 0000-00-00 00:00für beide Spalten fest.

JoeyD473
quelle

Antworten:

310

Da es sich um einen unformatierten Ausdruck handelt, sollten Sie DB::raw()Folgendes CURRENT_TIMESTAMPals Standardwert für eine Spalte festlegen :

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

Dies funktioniert einwandfrei auf jedem Datenbanktreiber.

Neue Verknüpfung

Ab Laravel 5.1.25 (siehe PR 10962 und Commit 15c487fe ) können Sie die neue useCurrent()Spaltenmodifikatormethode verwenden, um den CURRENT_TIMESTAMPStandardwert für eine Spalte festzulegen :

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

Zurück zur Frage, unter MySQL können Sie die ON UPDATEKlausel auch verwenden durch DB::raw():

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

Fallstricke

  • MySQL

    Ab MySQL 5.7 0000-00-00 00:00:00gilt kein gültiges Datum mehr. Wie im Upgrade-Handbuch für Laravel 5.2 dokumentiert , sollten alle Zeitstempelspalten einen gültigen Standardwert erhalten, wenn Sie Datensätze in Ihre Datenbank einfügen. Sie können den useCurrent()Spaltenmodifikator (ab Laravel 5.1.25 und höher) in Ihren Migrationen verwenden, um die Zeitstempelspalten auf die aktuellen Zeitstempel zu setzen, oder Sie können die Zeitstempel so einstellen nullable(), dass Nullwerte zulässig sind.

  • PostgreSQL & Laravel 4.x

    In Laravel 4.x-Versionen verwendete der PostgreSQL-Treiber die Standarddatenbankgenauigkeit zum Speichern von Zeitstempelwerten. Wenn Sie die CURRENT_TIMESTAMPFunktion für eine Spalte mit einer Standardgenauigkeit verwenden, generiert PostgreSQL einen Zeitstempel mit der höheren verfügbaren Genauigkeit und generiert so einen Zeitstempel mit einem Bruchteil des zweiten Teils - siehe diese SQL-Geige .

    Dies führt dazu, dass Carbon einen Zeitstempel nicht analysiert, da nicht erwartet wird, dass Mikrosekunden gespeichert werden. Um zu vermeiden, dass dieses unerwartete Verhalten Ihre Anwendung beschädigt, müssen Sie der CURRENT_TIMESTAMPFunktion wie folgt explizit eine Genauigkeit von Null geben :

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

    Seit Laravel 5.0 wurden timestamp()Spalten geändert, um eine Standardgenauigkeit von Null zu verwenden, wodurch dies vermieden wird.

    Vielen Dank an @andrewhl für den Hinweis auf dieses Problem in den Kommentaren.

Paulo Freitas
quelle
Viel besserer Vorschlag als meiner. Verwenden Sie dies anstelle meines DB::statementBeispiels, dies ist viel einfacher.
Marwelln
Kann dies auch für PARTITION BY-Anweisungen in Ihren Tests verwendet werden?
Glenn Plas
2
Nicht fehlerfrei. Für PostgreSQL gibt 'CURRENT_TIMESTAMP' etwas im Format zurück: 2014-08-11 15: 06: 29.692439. Dies führt dazu, dass die Carbon :: createFromFormat-Methode ('Ymd H: i: s', $ timestamp) fehlschlägt (die nachfolgenden Millisekunden können nicht analysiert werden). Dies wird von Laravel beim Zugriff auf Zeitstempel verwendet. Verwenden Sie zum Korrigieren von PostgreSQL: DB :: raw ('now () :: timestamp (0)') (Referenz: postgresql.org/docs/8.1/static/… )
andrewhl
@andrewhl Eigentlich habe ich nur für MySQL geantwortet, da es das Fragethema ist. Aber danke, dass Sie uns dies mitgeteilt haben. Ich werde meine Antwort aktualisieren, um dies zu behandeln! :)
Paulo Freitas
55

So erstellen Sie sowohl das created_atals auchupdated_at Spalten:

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

Sie benötigen MySQL Version> = 5.6.5, um mehrere Spalten mit zu haben CURRENT_TIMESTAMP

Brian Adams
quelle
3
Warum nicht einfach benutzen $table->timestamps()->default(DB::raw('CURRENT_TIMESTAMP'));?
Dave
1
@dave Weil sich dann updated_atnicht ändern würde, wenn der Datensatz nach seiner ersten Erstellung geändert wurde
Erik Berkun-Drevnig
Ja, fügen Sie hinzu, dass Zeitstempel () sowieso keine Standardeinstellungen zulassen, so dass das überhaupt nicht funktionieren würde. Ich hatte Code festgeschrieben, um dies zuzulassen, aber die Laravel-Manager möchten nicht, dass Benutzer die Standardeinstellungen so verwenden, wie wir sie verwenden (vorausgesetzt, Versionen von MySQL vor 5.6.5 erlauben nicht mehrere Spalten mit Standardstempeln).
Dave
Tatsächlich wird das update_at von Eloquent verwaltet, sodass das Bit "on update" überhaupt nicht erforderlich ist, da es gesetzt wird, wenn ein Modell automatisch aktualisiert wird.
Dmyers
@dmyers Wenn Sie eloquent verwenden, können Sie dies einfach tun, $t->timestamps();aber das beantwortet die Frage nicht.
Brian Adams
44

Ab Laravel 5.1.26, markiert am 02.12.2015, wurde ein useCurrent()Modifikator hinzugefügt:

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

PR 10962 (gefolgt von Commit 15c487fe ) führte zu diesem Zusatz.

Möglicherweise möchten Sie auch die Ausgaben 3602 und 11518 lesen die von Interesse sind.

Grundsätzlich müssen Sie in MySQL 5.7 (mit Standardkonfiguration) entweder einen Standardwert definieren oder für Zeitfelder nullwertfähig sein.

Gras Double
quelle
10

Das funktioniert nicht für eine Tatsache:

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

Es entfernt nicht die 'Standard 0', die mit der Auswahl des Zeitstempels zu kommen scheint, und fügt nur den benutzerdefinierten Standard hinzu. Aber wir brauchen es irgendwie ohne die Zitate. Nicht alles, was eine Datenbank manipuliert, stammt von Laravel4. Das ist sein Punkt. Er möchte benutzerdefinierte Standardeinstellungen für bestimmte Spalten wie:

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

Ich denke nicht, dass es mit Laravel möglich ist. Ich habe jetzt seit einer Stunde gesucht, um zu sehen, ob es möglich ist.


Update: Paulos Freitas Antwort zeigt, dass es möglich ist, aber die Syntax ist nicht einfach.

Glenn Plas
quelle
Toll. Perfektes Zeug. Daumen hoch, das hat mir auch geholfen.
Glenn Plas
kleine Bemerkung, bevor Sie schreien: Dies funktioniert bei mir in Laravel nicht. Sehen Sie sich das Datum an, an dem diese Antwort geschrieben wurde: 2013. Sie war damals gültig. Ich würde es begrüßen, bevor Sie auf den Abwärtspfeil tippen.
Glenn Plas
9

Als zusätzliche Möglichkeit für zukünftige Googler

Ich finde es nützlicher, null in der Spalte "update_at" zu haben, wenn der Datensatz erstellt, aber nie geändert wurde . Es reduziert die Datenbankgröße (ok, nur ein wenig) und es ist auf den ersten Blick erkennbar, dass die Daten nie geändert wurden.

Ab diesem Zeitpunkt benutze ich:

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

(In Laravel 7 mit MySQL 8).

ndberg
quelle
7

Verwenden Sie stattdessen den Vorschlag von Paulo Freitas .


Bis Laravel dies behebt, können Sie nach der Ausführung eine Standard-Datenbankabfrage Schema::createausführen.

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

Es hat Wunder für mich gewirkt.

Marwelln
quelle
Das ist ein schöner Trick. Ich wünschte, der Schema-Generator würde partitionierte Tabellen unterstützen, da ich diese überall verwende. Ich habe versucht, in den Code zu graben, aber es ist mir nicht so klar, wo ich das ändern soll.
Glenn Plas
-2

So machst du es, ich habe es überprüft und es funktioniert auf meinem Laravel 4.2.

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

Hoffe das hilft.

Jawad
quelle
-4

In Laravel 5 einfach:

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

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

JoenMarz
quelle
12
Dies setzt jedoch nicht den Standardwert CURRENT_TIMESTAMP, wie in der Frage gestellt.
Josh
Ich versuche dies in, aber gegeben null in 5.4 idk warum, aber wenn ich versuche -> useCurrent (); seine Arbeit gut
Anthony Kal
beantwortet die Frage von CURRENT_TIMESTAMPon created_atcolumn und on UPDATE CURRENT_TIMESTAMPon updated_atcolumn nicht. Bis Leute bei Laravel es reparieren, verwenden Sie dieses: $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP')); $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
Hamza Rashid