Comment puis-je définir la valeur par défaut d'une colonne d'horodatage sur l'horodatage actuel avec les migrations Laravel?

168

Je voudrais créer une colonne d'horodatage avec une valeur par défaut d' CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPutilisation de Laravel Schema Builder / Migrations. J'ai parcouru la documentation Laravel plusieurs fois, et je ne vois pas comment je peux en faire la valeur par défaut pour une colonne d'horodatage.

La timestamps()fonction définit les valeurs 0000-00-00 00:00par défaut pour les deux colonnes qu'elle crée.

JoeyD473
la source

Réponses:

310

Étant donné qu'il s'agit d'une expression brute, vous devez utiliser DB::raw()pour définir CURRENT_TIMESTAMPcomme valeur par défaut pour une colonne:

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

Cela fonctionne parfaitement sur chaque pilote de base de données.

Nouveau raccourci

Depuis Laravel 5.1.25 (voir PR 10962 et commit 15c487fe ), vous pouvez utiliser la nouvelle useCurrent()méthode de modificateur de colonne pour définir CURRENT_TIMESTAMPcomme valeur par défaut pour une colonne:

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

De retour à la question, sur MySQL, vous pouvez également utiliser la ON UPDATEclause via DB::raw():

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

Gotchas

  • MySQL

    À partir de MySQL 5.7, 0000-00-00 00:00:00n'est plus considéré comme une date valide. Comme indiqué dans le guide de mise à niveau de Laravel 5.2 , toutes les colonnes d'horodatage doivent recevoir une valeur par défaut valide lorsque vous insérez des enregistrements dans votre base de données. Vous pouvez utiliser le useCurrent()modificateur de colonne (à partir de Laravel 5.1.25 et supérieur) dans vos migrations pour définir par défaut les colonnes d'horodatage sur les horodatages actuels, ou vous pouvez créer les horodatages nullable()pour autoriser les valeurs nulles.

  • PostgreSQL et Laravel 4.x

    Dans les versions Laravel 4.x, le pilote PostgreSQL utilisait la précision de base de données par défaut pour stocker les valeurs d'horodatage. Lors de l'utilisation de la CURRENT_TIMESTAMPfonction sur une colonne avec une précision par défaut, PostgreSQL génère un horodatage avec la plus grande précision disponible, générant ainsi un horodatage avec une fraction de seconde partie - voir ce violon SQL .

    Cela conduira Carbon à échouer l'analyse d'un horodatage car il ne s'attendra pas à ce que les microsecondes soient stockées. Pour éviter que ce comportement inattendu ne casse votre application, vous devez explicitement donner une précision nulle à la CURRENT_TIMESTAMPfonction comme ci-dessous:

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

    Depuis Laravel 5.0, les timestamp()colonnes ont été modifiées pour utiliser une précision par défaut de zéro, ce qui évite cela.

    Merci à @andrewhl d' avoir signalé ce problème dans les commentaires.

Paulo Freitas
la source
Bien meilleure suggestion que la mienne. Utilisez ceci au lieu de mon DB::statementexemple, c'est beaucoup plus simple.
Marwelln
Cela peut-il également être utilisé pour les instructions PARTITION BY dans vos tests?
Glenn Plas
2
Pas parfaitement. Pour PostgreSQL 'CURRENT_TIMESTAMP' renvoie quelque chose au format: 2014-08-11 15: 06: 29.692439. Cela provoque l'échec de la méthode Carbon :: createFromFormat ('Ymd H: i: s', $ timestamp) (elle ne peut pas analyser les millisecondes de fin). Ceci est utilisé par Laravel lors de l'accès aux horodatages. Pour corriger PostgreSQL, utilisez: DB :: raw ('now () :: timestamp (0)') (référence: postgresql.org/docs/8.1/static/… )
andrewhl
@andrewhl En fait, j'ai répondu uniquement pour MySQL, puisque c'est le sujet de la question. Mais merci de partager cela avec nous, je mettrai à jour ma réponse pour couvrir cela! :)
Paulo Freitas
55

Pour créer à la fois les colonnes created_atet updated_at:

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

Vous aurez besoin de la version MySQL> = 5.6.5 pour avoir plusieurs colonnes avec CURRENT_TIMESTAMP

Brian Adams
la source
3
Pourquoi ne pas simplement utiliser $table->timestamps()->default(DB::raw('CURRENT_TIMESTAMP'));?
dave
1
@dave Parce que updated_atcela ne changerait pas lorsque l'enregistrement a été modifié après sa création initiale
Erik Berkun-Drevnig
Ouais, ajouter à cela les horodatages () ne permet de toute façon pas les valeurs par défaut, donc cela ne fonctionnerait pas du tout. J'avais commis du code pour l'autoriser, mais les gestionnaires Laravel ne veulent pas vraiment que les gens utilisent par défaut la façon dont nous l'utilisons (en supposant que les versions de MySQL antérieures à 5.6.5 n'autorisent pas plusieurs colonnes qui ont des horodatages par défaut).
dave
En fait, updated_at est géré par Eloquent, il n'y a donc pas du tout besoin du bit "on update" puisqu'il sera défini lorsqu'un modèle est mis à jour automatiquement.
dmyers
@dmyers Si vous utilisez éloquent, vous pouvez le faire, $t->timestamps();mais cela ne répond pas à la question.
Brian Adams
44

À partir de Laravel 5.1.26, tagué le 02/12/2015, un useCurrent()modificateur a été ajouté:

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

Le PR 10962 (suivi du commit 15c487fe ) a conduit à cet ajout.

Vous pouvez également lire les numéros 3602 et 11518 qui vous intéressent.

Fondamentalement, MySQL 5.7 (avec la configuration par défaut) vous oblige à définir une valeur par défaut ou Nullable pour les champs de temps.

Gras Double
la source
10

Cela ne fonctionne pas pour un fait:

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

Il ne supprime pas le «0 par défaut» qui semble venir avec la sélection de l'horodatage et ajoute simplement la valeur par défaut personnalisée. Mais nous en avons besoin sans les guillemets. Tout ce qui manipule une base de données ne vient pas de Laravel4. C'est son point. Il veut des valeurs par défaut personnalisées sur certaines colonnes comme:

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

Je ne pense pas que ce soit possible avec Laravel. Je cherche depuis une heure maintenant pour voir si c'est possible.


Mise à jour: la réponse de Paulos Freita montre que c'est possible, mais la syntaxe n'est pas simple.

Glenn Plas
la source
Génial. Des trucs parfaits. Bravo, cela m'a aidé aussi.
Glenn Plas
petite remarque, avant de crier: cela ne fonctionne pas pour moi dans laravel, jetez un œil à la date à laquelle cette réponse a été écrite: 2013. C'était valable à l'époque. J'apprécierais que vous appuyiez sur la flèche vers le bas.
Glenn Plas
10

Comme possibilité supplémentaire pour les futurs googleurs

Je trouve plus utile d'avoir null dans la colonne updated_at lorsque l'enregistrement est créé mais n'a jamais été modifié . Cela réduit la taille de la base de données (ok, juste un peu) et il est possible de voir à première vue que les données n'ont jamais été modifiées.

À partir de là, j'utilise:

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

(Dans Laravel 7 avec mysql 8).

ndberg
la source
7

Utilisez plutôt la suggestion de Paulo Freitas .


Jusqu'à ce que Laravel corrige cela, vous pouvez exécuter une requête de base de données standard après Schema::createavoir été exécuté.

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

Cela a fonctionné à merveille pour moi.

Marwelln
la source
C'est une belle astuce. Je souhaite que le constructeur de schéma prenne en charge les tables partitionnées car j'utilise celles-ci partout. J'ai essayé de fouiller dans le code mais ce n'est pas si évident pour moi de modifier cela.
Glenn Plas
-2

Voici comment vous faites, je l'ai vérifié et cela fonctionne sur mon Laravel 4.2.

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

J'espère que cela t'aides.

Jawad
la source
-5

Dans Laravel 5 simplement:

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

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

JoenMarz
la source
13
Mais cela ne définit pas la valeur par défaut comme CURRENT_TIMESTAMP comme demandé dans la question.
Josh
j'essaye ceci dans, mais donné null dans 5.4 idk pourquoi, mais quand j'essaye -> useCurrent (); son travail bien
Anthony Kal
ne répond pas à la question de CURRENT_TIMESTAMPsur created_atcolonne et on UPDATE CURRENT_TIMESTAMPsur updated_atcolonne. Jusqu'à ce que les gens de Laravel le réparent, utilisez ceci: $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP')); $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
Hamza Rashid