【问题标题】:How Can I Set the Default Value of a Timestamp Column to the Current Timestamp with Laravel Migrations?如何使用 Laravel 迁移将时间戳列的默认值设置为当前时间戳?
【发布时间】:2013-08-06 17:13:59
【问题描述】:

我想使用 Laravel Schema Builder/Migrations 创建一个默认值为 CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 的时间戳列。我已经多次浏览 Laravel 文档,但我不知道如何将其设为时间戳列的默认值。

timestamps() 函数为它创建的两列设置默认值 0000-00-00 00:00

【问题讨论】:

    标签: php mysql laravel laravel-4 laravel-5


    【解决方案1】:

    这对事实不起作用:

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

    它不会删除似乎与选择时间戳一起出现的“默认 0”,它只是附加了自定义默认值。但我们有点需要它没有引号。并非所有操作数据库的东西都来自 Laravel4。这就是他的观点。他希望在某些列上使用自定义默认值,例如:

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

    我认为 Laravel 不可能。我一直在寻找一个小时,看看是否有可能。


    更新: Paulos Freita 的answer 表明这是可能的,但语法并不简单。

    【讨论】:

    • 小话,在大喊大叫之前:这对我在 laravel 中不起作用,看看这个答案的撰写日期:2013。当时它是​​有效的。在您点击向下箭头之前,我将不胜感激。
    【解决方案2】:

    改用 Paulo Freitas suggestion


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

    这对我来说很神奇。

    【讨论】:

    • 这是一个不错的技巧。我希望架构生成器支持分区表,因为我在所有地方都使用这些分区表。我尝试深入研究代码,但对我来说在哪里修改它并不那么明显。
    【解决方案3】:

    鉴于它是一个原始表达式,您应该使用DB::raw()CURRENT_TIMESTAMP 设置为列的默认值:

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

    这在每个数据库驱动程序上都能完美运行。

    从 Laravel 5.1.25 开始(参见 PR 10962commit 15c487fe),您现在可以使用新的 useCurrent() 列修饰符方法来为列实现相同的默认值:

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

    回到问题,在 MySQL 上你也可以通过DB::raw() 使用ON UPDATE 子句:

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

    同样,从 Laravel 8.36.0(参见 PR 36817)开始,您现在可以使用新的 useCurrentOnUpdate() 列修饰符方法和 useCurrent() 修饰符来为列实现相同的默认值:

    $table->timestamp('updated_at')->useCurrent()->useCurrentOnUpdate();
    

    陷阱

    • MySQL

      从 MySQL 5.7 开始,0000-00-00 00:00:00 不再被视为有效日期。如Laravel 5.2 upgrade guide 中所述,当您将记录插入数据库时​​,所有时间戳列都应接收有效的默认值。您可以在迁移中使用 useCurrent() 列修饰符(来自 Laravel 5.1.25 及更高版本)将时间戳列默认为当前时间戳,或者您可以将时间戳 nullable() 设置为允许空值。

    • PostgreSQL 和 Laravel 4.x

      在 Laravel 4.x 版本中,PostgreSQL 驱动程序使用默认的数据库精度来存储时间戳值。当在具有默认精度的列上使用 CURRENT_TIMESTAMP 函数时,PostgreSQL 会生成具有更高可用精度的时间戳,从而生成带有小数秒部分的时间戳 - see this SQL fiddle

      这将导致 Carbon 无法解析时间戳,因为它不会期望存储微秒。为避免这种意外行为破坏您的应用程序,您必须明确地为 CURRENT_TIMESTAMP 函数指定零精度,如下所示:

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

      自 Laravel 5.0 起,timestamp() 列已更改为使用默认精度为零,从而避免了这种情况。

    感谢 @andrewhl 指出 cmets 中的 Laravel 4.x 问题。

    感谢 @ChanakaKarunarathne 在 cmets 中推出新的 useCurrentOnUpdate() 快捷方式。

    【讨论】:

    • 这也可以用于您的测试中的 PARTITION BY 语句吗?
    • 并非完美无缺。对于 PostgreSQL 'CURRENT_TIMESTAMP' 返回格式为:2014-08-11 15:06:29.692439。这会导致 Carbon::createFromFormat('Y-m-d H:i:s', $timestamp) 方法失败(它无法解析尾随毫秒)。这是 Laravel 在访问时间戳时使用的。要修复 PostgreSQL,请使用:DB::raw('now()::timestamp(0)')(参考:postgresql.org/docs/8.1/static/…
    【解决方案4】:

    创建created_atupdated_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 的列

    【讨论】:

    • 为什么不直接使用$table->timestamps()->default(DB::raw('CURRENT_TIMESTAMP'));
    • @dave 因为这样updated_at 在初始创建后修改记录时不会更改
    • 是的,加上 timestamps() 无论如何都不允许默认值,所以这根本行不通。我已经提交了代码来允许它,但是 Laravel 管理器并不真正希望人们使用我们使用它的方式默认(假设因为 5.6.5 之前的 MySQL 版本不允许具有默认时间戳的多个列)。
    • 实际上 updated_at 由 Eloquent 管理,因此根本不需要“on update”位,因为它会在模型​​自动更新时设置。
    • @dmyers 如果您使用的是 eloquent,那么您可以使用 $t->timestamps(); 但这并不能回答问题。
    【解决方案5】:

    这就是你的做法,我已经检查过了,它适用于我的 Laravel 4.2。

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

    希望这会有所帮助。

    【讨论】:

      【解决方案6】:

      从 Laravel 5.1.26 开始,标记于 2015-12-02,添加了 useCurrent() 修饰符:

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

      PR 10962(后跟commit 15c487fe)导致了此添加。

      您可能还想阅读感兴趣的问题360211518

      基本上,MySQL 5.7(带有默认配置)要求您为时间字段定义默认值或可为空。

      【讨论】:

        【解决方案7】:

        在 Laravel 5 中:

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

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

        【讨论】:

        • 但这并没有按照问题中的要求将默认设置为 CURRENT_TIMESTAMP。
        • 我尝试了这个,但在 5.4 idk 中给出了 null 为什么,但是当我尝试时 ->useCurrent();它的工作正常
        • 不回答created_at 列上的CURRENT_TIMESTAMPupdated_at 列上的on UPDATE CURRENT_TIMESTAMP 的问题。直到 Laravel 的人修复它,使用这个:$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));$table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
        【解决方案8】:

        为未来的谷歌员工提供额外的可能性

        我发现在创建记录但从未修改过时在 updated_at 列中包含 null 更有用。它减少了 db 大小(好吧,只是一点点),并且可以第一眼看到数据从未被修改过。

        我现在使用:

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

        (在带有 mysql 8 的 Laravel 7 中)。

        【讨论】:

        • 我真的很喜欢这个主意。在某些情况下,在未修改的记录中包含 updates_at = null 会非常有用
        • 有史以来最好的东西,更符合更新的名称
        【解决方案9】:

        如果您要为 dateTime 列设置当前日期时间(就像我在谷歌上搜索时一样),请使用这种方式

        $table->dateTime('signed_when')->useCurrent();
        

        【讨论】:

          【解决方案10】:

          在 laravel 7 中,设置当前时间使用以下:

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

          【讨论】:

            【解决方案11】:

            我在 Laravel 中使用以下自定义:

            1. 默认 created_at 为当前时间戳
            2. 更新记录时更新时间戳

            首先,我将在 Laravel 的根目录中创建一个文件 helpers.php 并插入以下内容:

            <?php
            
            if (!function_exists('database_driver')) {
                function database_driver(): string
                {
                    $connection = config('database.default');
                    return config('database.connections.' . $connection . '.driver');
                }
            }
            
            if (!function_exists('is_database_driver')) {
                function is_database_driver(string $driver): bool
                {
                    return $driver === database_driver();
                }
            }
            

            在 composer.json 中,我将以下内容插入autoload。这允许作曲家自动发现 helpers.php。

                "autoload": {
                    "files": [
                        "app/Services/Uploads/Processors/processor_functions.php",
                        "app/helpers.php"
                    ]
                },
            

            我在我的 Laravel 模型中使用以下内容。

                    if (is_database_driver('sqlite')) {
                        $table->timestamps();
                    } else {
                        $table->timestamp('created_at')->default(\DB::raw('CURRENT_TIMESTAMP'));
                        $table->timestamp('updated_at')
                            ->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
                    }
            

            这让我的团队可以继续使用 sqlite 进行单元测试。 ON UPDATE CURRENT_TIMESTAMP 是 MySQL 快捷方式,在 sqlite 中不可用。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-05-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-11-26
              • 1970-01-01
              • 1970-01-01
              • 2016-12-18
              相关资源
              最近更新 更多