Как я могу установить значение по умолчанию столбца метки времени на текущую метку времени с миграциями Laravel?

168

Я хотел бы создать столбец меток времени со значением по умолчанию, CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPиспользующим Laravel Schema Builder / Migrations. Я просматривал документацию Laravel несколько раз и не вижу, как сделать это по умолчанию для столбца метки времени.

timestamps()Функция делает по умолчанию 0000-00-00 00:00для обеих колонок , что он делает.

JoeyD473
источник

Ответы:

310

Учитывая, что это необработанное выражение, вы должны использовать DB::raw()его CURRENT_TIMESTAMPв качестве значения по умолчанию для столбца:

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

Это работает безупречно на каждом драйвере базы данных.

Новый ярлык

Начиная с Laravel 5.1.25 (см. PR 10962 и коммит 15c487fe ), вы можете использовать новый useCurrent()метод модификатора столбца, чтобы установить CURRENT_TIMESTAMPзначение по умолчанию для столбца:

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

Возвращаясь к вопросу, на MySQL вы также можете использовать ON UPDATEпредложение через DB::raw():

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

Gotchas

  • MySQL

    Начиная с MySQL 5.7, 0000-00-00 00:00:00более не считается действительной датой. Как описано в руководстве по обновлению Laravel 5.2 , все столбцы меток времени должны получать действительное значение по умолчанию при вставке записей в базу данных. Вы можете использовать useCurrent()модификатор столбца (от Laravel 5.1.25 и выше) в своих миграциях, чтобы по умолчанию столбцы отметок времени указывали текущие отметки времени, или вы можете сделать отметки времени, nullable()чтобы разрешить нулевые значения.

  • PostgreSQL и Laravel 4.x

    В версиях Laravel 4.x драйвер PostgreSQL использовал точность базы данных по умолчанию для хранения значений меток времени. При использовании CURRENT_TIMESTAMPфункции для столбца с точностью по умолчанию PostgreSQL генерирует временную метку с более высокой доступной точностью, таким образом генерируя временную метку с дробной второй частью - см. Эту скрипту SQL .

    Это приведет к тому, что Carbon потерпит неудачную обработку метки времени, поскольку он не будет ожидать сохранения микросекунд. Чтобы избежать этого неожиданного поведения, нарушающего работу вашего приложения, вы должны явно дать нулевую точность CURRENT_TIMESTAMPфункции, как показано ниже:

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

    Начиная с Laravel 5.0, timestamp()столбцы были изменены для использования точности по умолчанию, равной нулю, что позволяет избежать этого.

    Спасибо @andrewhl за указание на эту проблему в комментариях.

Пауло Фрейтас
источник
Лучше предложение, чем мое. Используйте это вместо моего DB::statementпримера, это намного проще.
Marwelln
Может ли это также использоваться для операторов PARTITION BY в ваших тестах?
Гленн Плас
2
Не без нареканий. Для PostgreSQL CURRENT_TIMESTAMP возвращает что-то в формате: 2014-08-11 15: 06: 29.692439. Это приводит к сбою метода Carbon :: createFromFormat ('Ymd H: i: s', $ timestamp) (он не может проанализировать завершающие миллисекунды). Это используется Laravel при доступе к временным меткам. Для исправления PostgreSQL используйте: DB :: raw ('now () :: timestamp (0)') (ссылка: postgresql.org/docs/8.1/static/… )
andrewhl
@andrewhl На самом деле я отвечал только за MySQL, так как это тема вопроса. Но спасибо, что поделились этим с нами, я обновлю свой ответ, чтобы покрыть это! :)
Пауло Фрейтас
55

Для того, чтобы создать как из created_atи updated_atстолбцов:

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

Вам потребуется версия MySQL> = 5.6.5, чтобы иметь несколько столбцов с CURRENT_TIMESTAMP

Брайан Адамс
источник
3
Почему бы просто не использовать $table->timestamps()->default(DB::raw('CURRENT_TIMESTAMP'));?
Дэйв
1
@dave Потому что тогда updated_atне изменится, когда запись была изменена после ее первоначального создания
Эрик Беркун-Древниг
Да, добавить к этому timestamps () не позволяет значения по умолчанию, так что это не будет работать вообще. Я зафиксировал код, чтобы разрешить это, но менеджеры Laravel на самом деле не хотят, чтобы люди использовали стандарт по умолчанию так, как мы его используем (при условии, что версии MySQL до 5.6.5 не допускают использование нескольких столбцов с временными метками по умолчанию).
Дэйв
Фактически, updated_at управляется Eloquent, поэтому бит «при обновлении» вообще не нужен, поскольку он будет установлен при автоматическом обновлении модели.
dmyers
@dmyers Если вы используете eloquent, вы можете просто сделать, $t->timestamps();но это не отвечает на вопрос.
Брайан Адамс
44

Начиная с Laravel 5.1.26, отмеченного 2015-12-02, добавлен useCurrent()модификатор:

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

PR 10962 (сопровождаемый коммитом 15c487fe ) привел к этому добавлению.

Вы также можете прочитать выпуски 3602 и 11518, которые представляют интерес.

По сути, MySQL 5.7 (с конфигурацией по умолчанию) требует, чтобы вы определяли либо значение по умолчанию, либо значение NULL для полей времени.

Гра двухместный
источник
10

Это не работает на самом деле:

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

Он не удаляет «по умолчанию 0», который, кажется, идет с выбором метки времени, а просто добавляет пользовательское значение по умолчанию. Но нам это нужно без кавычек. Не все, что манипулирует БД, исходит от Laravel4. Это его точка зрения. Он хочет использовать пользовательские настройки по умолчанию для определенных столбцов, таких как:

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

Я не думаю, что это возможно с Laravel. Я искал час, чтобы посмотреть, возможно ли это.


Обновление: ответ Паулоса Фрейты показывает, что это возможно, но синтаксис не прост.

Гленн Плас
источник
Отлично. Прекрасные вещи. Недурно, мне это тоже помогло.
Гленн Плас
Небольшое замечание, прежде чем кричать: это не работает для меня в laravel, взгляните на дату, когда был написан этот ответ: 2013 год. Тогда он был действителен. Я был бы признателен, прежде чем нажать стрелку вниз.
Гленн Плас
10

Как дополнительная возможность для будущих гуглеров

Я считаю более полезным иметь значение NULL в столбце updated_at, когда запись создана, но никогда не изменялась . Это уменьшает размер БД (хорошо, только немного) и его можно увидеть с первого взгляда, что данные никогда не изменялись.

По состоянию на это я использую:

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

(В Laravel 7 с MySQL 8).

ndberg
источник
7

Вместо этого используйте предложение Пауло Фрейтаса .


Пока Laravel не исправит это, вы можете запустить стандартный запрос к базе данных после того, как 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");

Это творило чудеса для меня.

Marwelln
источник
Это хороший трюк. Я хотел бы, чтобы построитель схемы поддерживал секционированные таблицы, поскольку я использую их повсюду. Я попытался покопаться в коде, но для меня не так очевидно, где это мод.
Гленн Плас
-2

Вот как ты это делаешь, я проверил, и он работает на моем Laravel 4.2.

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

Надеюсь это поможет.

Джавад
источник
-5

В Laravel 5 просто:

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

Документация: http://laravel.com/docs/5.1/migrations#creating-columns

JoenMarz
источник
13
Но это не устанавливает значение по умолчанию как CURRENT_TIMESTAMP, как задано в вопросе.
Джош
я пытаюсь это сделать, но с учетом нуля в 5.4 IDK почему, но когда я пытаюсь -> useCurrent (); его работа отлично
Энтони Кэл
не отвечает на вопрос о том, CURRENT_TIMESTAMPна created_atколонке и on UPDATE CURRENT_TIMESTAMPна updated_atколонке. Пока люди в Laravel исправят это, используйте это: $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP')); $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
Хамза Рашид