Bagaimana Saya Dapat Mengatur Nilai Default Kolom Timestamp ke Stempel Waktu Saat Ini dengan Migrasi Laravel?

167

Saya ingin membuat kolom cap waktu dengan nilai default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPmenggunakan Pembuat Skema Laravel / Migrasi. Saya telah membaca dokumentasi Laravel beberapa kali, dan saya tidak melihat bagaimana saya dapat menjadikannya default untuk kolom cap waktu.

The timestamps()Fungsi membuat default 0000-00-00 00:00untuk kedua kolom yang membuat.

JoeyD473
sumber

Jawaban:

310

Mengingat itu ekspresi mentah, Anda harus menggunakan DB::raw()untuk menetapkan CURRENT_TIMESTAMPsebagai nilai default untuk kolom:

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

Ini berfungsi dengan sempurna pada setiap driver basis data.

Pintasan baru

Pada Laravel 5.1.25 (lihat PR 10962 dan komit 15c487fe ), Anda dapat menggunakan useCurrent()metode pengubah kolom baru untuk menetapkan CURRENT_TIMESTAMPsebagai nilai default untuk kolom:

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

Kembali ke pertanyaan, pada MySQL Anda juga dapat menggunakan ON UPDATEklausa melalui DB::raw():

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

Gotcha

  • MySQL

    Dimulai dengan MySQL 5.7, 0000-00-00 00:00:00tidak lagi dianggap sebagai tanggal yang valid. Seperti yang didokumentasikan di panduan peningkatan Laravel 5.2 , semua kolom stempel waktu harus menerima nilai default yang valid saat Anda memasukkan catatan ke dalam basis data Anda. Anda dapat menggunakan useCurrent()pengubah kolom (dari Laravel 5.1.25 dan di atas) dalam migrasi Anda untuk default kolom cap waktu ke cap waktu saat ini, atau Anda dapat membuat cap waktu nullable()untuk memungkinkan nilai nol.

  • PostgreSQL & Laravel 4.x

    Dalam versi Laravel 4.x, driver PostgreSQL menggunakan presisi database default untuk menyimpan nilai cap waktu. Ketika menggunakan CURRENT_TIMESTAMPfungsi pada kolom dengan presisi default, PostgreSQL menghasilkan timestamp dengan presisi yang lebih tinggi, sehingga menghasilkan timestamp dengan bagian kedua fraksional - lihat biola SQL ini .

    Ini akan menyebabkan Karbon gagal mengurai cap waktu karena tidak akan mengharapkan mikrodetik disimpan. Untuk menghindari perilaku tak terduga yang merusak aplikasi Anda, Anda harus secara eksplisit memberikan ketepatan nol untuk CURRENT_TIMESTAMPfungsi seperti di bawah ini:

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

    Sejak Laravel 5.0, timestamp()kolom telah diubah untuk menggunakan presisi default nol yang menghindari ini.

    Terima kasih kepada @andrewhl karena menunjukkan masalah ini di komentar.

Paulo Freitas
sumber
Saran yang jauh lebih baik dari saya. Gunakan ini sebagai ganti DB::statementcontoh saya , ini jauh lebih sederhana.
Marwelln
Bisakah ini juga digunakan untuk pernyataan PARTISI OLEH dalam pengujian Anda?
Glenn Plas
2
Tidak sempurna. Untuk PostgreSQL 'CURRENT_TIMESTAMP' mengembalikan sesuatu dalam format: 2014-08-11 15: 06: 29.692439. Ini menyebabkan metode Carbon :: createFromFormat ('Ymd H: i: s', $ timestamp) gagal (tidak dapat menguraikan milidetik trailing). Ini digunakan oleh Laravel ketika mengakses cap waktu. Untuk memperbaiki PostgreSQL, gunakan: DB :: raw ('now () :: timestamp (0)') (referensi: postgresql.org/docs/8.1/static/… )
andrewhl
@andrewhl Sebenarnya saya hanya menjawab untuk MySQL, karena itu adalah subjek pertanyaan. Tetapi terima kasih telah berbagi ini dengan kami, saya akan memperbarui jawaban saya untuk menutupinya! :)
Paulo Freitas
55

Untuk membuat kolom created_atdan keduanya updated_at:

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

Anda memerlukan versi MySQL> = 5.6.5 untuk memiliki banyak kolom CURRENT_TIMESTAMP

Brian Adams
sumber
3
Kenapa tidak pakai saja $table->timestamps()->default(DB::raw('CURRENT_TIMESTAMP'));?
dave
1
@dave Karena itu updated_attidak akan berubah ketika catatan itu diubah setelah penciptaan awal
Erik Berkun-Drevnig
Ya, tambahkan ke stempel waktu () itu tidak memungkinkan untuk default, jadi itu tidak akan berfungsi sama sekali. Saya telah melakukan kode untuk mengizinkannya, tetapi manajer Laravel tidak benar-benar ingin orang menggunakan default seperti yang kita gunakan (dengan asumsi karena versi MySQL sebelum 5.6.5 tidak mengizinkan beberapa kolom yang memiliki cap waktu sebagai default).
dave
Sebenarnya updated_at dikelola oleh Eloquent sehingga sama sekali tidak perlu untuk bit "on update" karena itu akan ditetapkan ketika model diperbarui secara otomatis.
dmyers
@dmyers Jika Anda menggunakan fasih maka Anda bisa melakukannya $t->timestamps();tetapi itu tidak menjawab pertanyaan.
Brian Adams
44

Mulai dari Laravel 5.1.26, ditandai pada 2015-12-02, useCurrent()pengubah telah ditambahkan:

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

PR 10962 (diikuti oleh commit 15c487fe ) mengarah ke penambahan ini.

Anda mungkin juga ingin membaca masalah 3602 dan 11518 yang menarik.

Pada dasarnya, MySQL 5.7 (dengan konfigurasi default) mengharuskan Anda untuk menentukan nilai default atau nullable untuk bidang waktu.

Gras Double
sumber
10

Ini tidak bekerja untuk fakta:

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

Itu tidak menghapus 'default 0' yang tampaknya datang dengan memilih stempel waktu dan itu hanya menambahkan standar kustom. Tapi kami membutuhkannya tanpa tanda kutip. Tidak semua yang memanipulasi DB berasal dari Laravel4. Itu intinya. Dia ingin standar kustom pada kolom tertentu seperti:

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

Saya tidak berpikir itu mungkin dengan Laravel. Saya sudah mencari satu jam sekarang untuk melihat apakah itu mungkin.


Update: Paulos Freita ini jawaban menunjukkan bahwa adalah mungkin, tetapi sintaks tidak langsung.

Glenn Plas
sumber
Bagus. Hal yang sempurna. Jempol, ini membantu saya juga.
Glenn Plas
sedikit komentar, sebelum berteriak: ini tidak bekerja untuk saya di laravel, lihat tanggal jawaban ini ditulis: 2013. Itu berlaku saat itu. Saya akan sangat menghargai sebelum Anda mengetuk panah bawah.
Glenn Plas
9

Sebagai kemungkinan tambahan untuk googler masa depan

Saya merasa lebih bermanfaat untuk memiliki null di kolom updated_at ketika catatan dibuat tetapi belum pernah dimodifikasi . Ini mengurangi ukuran db (ok, hanya sedikit) dan memungkinkan untuk melihatnya pada pandangan pertama bahwa data tidak pernah dimodifikasi.

Sampai saat ini saya menggunakan:

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

(Dalam Laravel 7 dengan mysql 8).

ndberg
sumber
7

Gunakan saran Paulo Freitas sebagai gantinya.


Sampai Laravel memperbaiki ini, Anda dapat menjalankan kueri basis data standar setelah Schema::createdijalankan.

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

Itu bekerja keajaiban bagi saya.

Marwelln
sumber
Itu trik yang bagus. Saya berharap pembuat skema didukung tabel dipartisi karena saya menggunakan mereka di semua tempat. Saya mencoba menggali ke dalam kode tetapi tidak jelas bagi saya di mana mod ini.
Glenn Plas
-2

Ini adalah bagaimana Anda melakukannya, saya telah memeriksanya dan berfungsi pada Laravel 4.2 saya.

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

Semoga ini membantu.

Jawad
sumber
-4

Dalam Laravel 5 secara sederhana:

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

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

JoenMarz
sumber
12
Tetapi ini tidak menetapkan default sebagai CURRENT_TIMESTAMP seperti yang ditanyakan dalam pertanyaan.
Josh
saya coba ini, tetapi diberikan null pada 5.4 idk mengapa, tetapi ketika saya mencoba -> useCurrent (); ini berfungsi dengan baik
Anthony Kal
tidak menjawab pertanyaan dari CURRENT_TIMESTAMPpada created_atkolom dan on UPDATE CURRENT_TIMESTAMPpada updated_atkolom. Sampai orang-orang di Laravel memperbaikinya, gunakan ini: $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP')); $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
Hamza Rashid