Jak ustawić domyślną wartość kolumny sygnatury czasowej na bieżącą sygnaturę czasową za pomocą migracji Laravel?

168

Chciałbym utworzyć kolumnę ze znacznikiem czasu z domyślną wartością CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPużywania Laravel Schema Builder / Migrations. Kilka razy przejrzałem dokumentację Laravel i nie widzę, jak mogę ustawić to jako domyślne dla kolumny znacznika czasu.

timestamps()Funkcja sprawia, że ustawienia domyślne 0000-00-00 00:00dla obu kolumn, które to sprawia.

JoeyD473
źródło

Odpowiedzi:

310

Biorąc pod uwagę, że jest to surowe wyrażenie, należy użyć, DB::raw()aby ustawić CURRENT_TIMESTAMPjako domyślną wartość kolumny:

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

Działa to bezbłędnie na każdym sterowniku bazy danych.

Nowy skrót

Od Laravel 5.1.25 (patrz PR 10962 i zatwierdzenie 15c487fe ) możesz użyć nowej useCurrent()metody modyfikatora kolumn, aby ustawić CURRENT_TIMESTAMPjako domyślną wartość dla kolumny:

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

Wracając do pytania, w MySQL możesz również użyć ON UPDATEklauzuli poprzez DB::raw():

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

Gotchas

  • MySQL

    Począwszy od MySQL 5.7, 0000-00-00 00:00:00nie jest już uważany za prawidłową datę. Jak udokumentowano w przewodniku aktualizacji Laravel 5.2 , wszystkie kolumny ze znacznikami czasu powinny otrzymać prawidłową wartość domyślną podczas wstawiania rekordów do bazy danych. Możesz użyć useCurrent()modyfikatora kolumny (z Laravel 5.1.25 i nowszych) w swoich migracjach, aby ustawić domyślne kolumny znaczników czasu na bieżące znaczniki czasu lub możesz ustawić znaczniki czasu, nullable()aby zezwalały na wartości null.

  • PostgreSQL i Laravel 4.x

    W wersjach Laravel 4.x sterownik PostgreSQL używał domyślnej precyzji bazy danych do przechowywania wartości znaczników czasu. Używając CURRENT_TIMESTAMPfunkcji na kolumnie z domyślną precyzją, PostgreSQL generuje znacznik czasu z dostępną wyższą dokładnością, generując w ten sposób znacznik czasu z ułamkową drugą częścią - zobacz to skrzypce SQL .

    Spowoduje to, że Carbon nie będzie mógł przeanalizować znacznika czasu, ponieważ nie będzie oczekiwał przechowywania mikrosekund. Aby uniknąć tego nieoczekiwanego zachowania powodującego uszkodzenie aplikacji, musisz jawnie podać zerową precyzję CURRENT_TIMESTAMPfunkcji, jak poniżej:

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

    Od wersji Laravel 5.0 timestamp()kolumny zostały zmienione, aby używać domyślnej precyzji równej zero, co pozwala uniknąć tego.

    Podziękowania dla @andrewhl za wskazanie tego problemu w komentarzach.

Paulo Freitas
źródło
O wiele lepsza sugestia niż moja. Użyj tego zamiast mojego DB::statementprzykładu, to jest znacznie prostsze.
Marwelln,
Czy można tego również użyć w przypadku instrukcji PARTITION BY w testach?
Glenn Plas
2
Nie bezbłędnie. Dla PostgreSQL 'CURRENT_TIMESTAMP' zwraca coś w formacie: 2014-08-11 15: 06: 29.692439. Powoduje to niepowodzenie metody Carbon :: createFromFormat ('Ymd H: i: s', $ timestamp) (nie może przeanalizować końcowych milisekund). Jest to używane przez Laravel podczas uzyskiwania dostępu do znaczników czasu. Ustalenie dla PostgreSQL, przeznaczenie: DB :: RAW ( 'Now () :: timestamp (0)') (numer referencyjny: postgresql.org/docs/8.1/static/... )
andrewhl
@andrewhl Właściwie odpowiedziałem tylko za MySQL, ponieważ jest to temat pytania. Ale dzięki za podzielenie się tym z nami, zaktualizuję swoją odpowiedź, aby to uwzględnić! :)
Paulo Freitas
55

Aby utworzyć obie kolumny created_ati updated_at:

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

Będziesz potrzebować MySQL w wersji> = 5.6.5, aby mieć wiele kolumn z rozszerzeniem CURRENT_TIMESTAMP

Brian Adams
źródło
3
Dlaczego po prostu nie użyć $table->timestamps()->default(DB::raw('CURRENT_TIMESTAMP'));?
dave
1
@dave Ponieważ wtedy updated_atnie zmieniłoby się, gdy płyta została zmodyfikowana po jej początkowym utworzeniu
Erik Berkun-Drevnig
Tak, dodaj do tego timestamps () i tak nie zezwala na domyślne, więc to w ogóle nie zadziała. Zaakceptowałem kod, aby na to zezwolić, ale menedżerowie Laravel tak naprawdę nie chcą, aby ludzie używali domyślnego sposobu, w jaki go używamy (zakładając, że wersje MySQL wcześniejsze niż 5.6.5 nie zezwalają na wiele kolumn, które domyślnie mają znaczniki czasu).
dave
W rzeczywistości updated_at jest zarządzane przez Eloquent, więc nie ma potrzeby używania bitu „on update”, ponieważ zostanie ustawiony, gdy model zostanie zaktualizowany automatycznie.
dmyers
@dmyers Jeśli używasz elokwencji, możesz to zrobić, $t->timestamps();ale to nie odpowiada na pytanie.
Brian Adams
44

Począwszy od Laravel 5.1.26, oznaczonego dnia 2015-12-02, dodano useCurrent()modyfikator:

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

PR 10962 (po którym następuje commit 15c487fe ) doprowadził do tego dodania.

Możesz także przeczytać wydania 3602 i 11518, które Cię interesują.

Zasadniczo MySQL 5.7 (z domyślną konfiguracją) wymaga zdefiniowania wartości domyślnej lub wartości null dla pól czasu.

Gras Double
źródło
10

To nie działa na fakt:

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

Nie usuwa `` domyślnego 0 '', które wydaje się pochodzić z wybrania znacznika czasu, a po prostu dodaje niestandardowe ustawienie domyślne. Ale potrzebujemy tego bez cudzysłowów. Nie wszystko, co manipuluje bazą danych, pochodzi z Laravel4. To jego punkt widzenia. Chce niestandardowych ustawień domyślnych w niektórych kolumnach, takich jak:

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

Nie sądzę, że jest to możliwe w przypadku Laravel. Szukałem już godzinę, żeby zobaczyć, czy to możliwe.


Aktualizacja: odpowiedź Paulosa Freity pokazuje, że jest to możliwe, ale składnia nie jest prosta.

Glenn Plas
źródło
Wspaniały. Doskonała rzecz. Kciuki w górę, to też mi pomogło.
Glenn Plas
mała uwaga, zanim krzykniesz: to nie działa dla mnie w laravel, spójrz na datę napisania tej odpowiedzi: 2013. Była wtedy ważna. Byłbym wdzięczny, zanim dotkniesz strzałki w dół.
Glenn Plas
9

Jako dodatkowa możliwość dla przyszłych pracowników Google

Uważam, że bardziej przydatne jest ustawienie wartości null w kolumnie updated_at, gdy rekord jest tworzony, ale nigdy nie był modyfikowany . Zmniejsza rozmiar bazy danych (ok, tylko trochę) i na pierwszy rzut oka widać, że dane nigdy nie były modyfikowane.

Od tego czasu używam:

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

(W Laravel 7 z mysql 8).

ndberg
źródło
7

Zamiast tego skorzystaj z sugestii Paulo Freitas .


Dopóki Laravel tego nie naprawi, po uruchomieniu można uruchomić standardowe zapytanie do bazy danych Schema::create.

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

Zrobiło to dla mnie cuda.

Marwelln
źródło
To niezła sztuczka. Chciałbym, aby kreator schematów obsługiwał tabele partycjonowane, ponieważ używam ich w każdym miejscu. Próbowałem zagłębić się w kod, ale nie jest dla mnie takie oczywiste, gdzie to zmodyfikować.
Glenn Plas
-2

Tak to się robi, sprawdziłem to i działa na moim Laravelu 4.2.

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

Mam nadzieję że to pomoże.

Jawad
źródło
-5

W Laravel 5 po prostu:

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

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

JoenMarz
źródło
13
Ale to nie ustawia wartości domyślnej jako CURRENT_TIMESTAMP, jak zadano w pytaniu.
Josh
próbuję tego, ale podano null w 5.4 idk dlaczego, ale kiedy próbuję -> useCurrent (); działa dobrze
Anthony Kal
nie odpowiada na pytanie CURRENT_TIMESTAMPw created_atkolumnie i on UPDATE CURRENT_TIMESTAMPna updated_atkolumnie. Dopóki ludzie w Laravel nie naprawią tego, użyj tego: $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP')); $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
Hamza Rashid.