创建带有两个时间戳列的表时出现Laravel错误

马赫迪·安萨里(Mahdi J.Ansari)

我在Laravel 6.6中使用以下定义创建了一个表。

public function up()
{
    Schema::create('quarters', function (Blueprint $table) {
        $table->integer('quarter_id')->unsigned();
        $table->integer('year')->unsigned();
        $table->integer('quarter_num')->unsigned();
        $table->timestamp('valid_from');
        $table->timestamp('valid_to'); // <------ error on this line
        $table->string('description')->nullable();
        $table->timestamps();
        $table->primary('quarter_id');
    });
} 

当我运行迁移命令时,出现以下错误。

Illuminate \ Database \ QueryException:SQLSTATE [42000]:语法错误或访问冲突:1067“ valid_to”的默认值无效(SQL:创建表quartersquarter_idint unsigned not null,yearint unsigned not null,quarter_numint unsigned not null,valid_fromtimestamp not null,valid_to时间戳记不为null,descriptionvarchar(255)为null,created_at时间戳为null,updated_at时间戳为null)默认字符集utf8mb4整理为'utf8mb4_unicode_ci')

这是Eloquent生成的SQL:

CREATE TABLE `quarters`(
    `quarter_id` INT UNSIGNED NOT NULL,
    `year` INT UNSIGNED NOT NULL,
    `quarter_num` INT UNSIGNED NOT NULL,
    `valid_from` TIMESTAMP NOT NULL,
    `valid_to` TIMESTAMP NOT NULL,
    `description` VARCHAR(255) NULL,
    `created_at` TIMESTAMP NULL,
    `updated_at` TIMESTAMP NULL
) DEFAULT CHARACTER SET utf8mb4 COLLATE 'utf8mb4_unicode_ci'

奇怪的是,如果我注释掉该valid_to行,它将创建没有错误的表。但是的定义与valid_to100%相似valid_from,并且不会为该valid_from引发该错误实际上,似乎数据库不允许两timestamp列!

根据评论中的要求,我运行了php artisan migrate --pretend,结果如下:

C:\xampp\htdocs\voiceit> php artisan migrate --pretend
CreateQuartersTable: create table `quarters` (`quarter_id` int unsigned not null, `year` int unsigned not null, `quarter_num` int unsigned not null, `valid_from` timestamp not null, `valid_to` timestamp not null, `description` varchar(255) null, `created_at` timestamp null, `updated_at` timestamp null) default character set utf8mb4 collate 'utf8mb4_unicode_ci'
CreateQuartersTable: alter table `quarters` add primary key `quarters_quarter_id_primary`(`quarter_id`)
CreatePeopleDatasTable: create table `people_datas` (`mt_id` bigint unsigned not null, `valid_for` int unsigned not null, `local_personal_id` bigint unsigned not null, `first_name` varchar(255) not null, `last_name` varchar(255) not null, `date_of_birth` date null, `date_of_join` date null, `gender` varchar(1) not null, `location_type` varchar(1) not null, `created_at` timestamp null, `updated_at` timestamp null, `deleted_at` timestamp null) default character set utf8mb4 collate 'utf8mb4_unicode_ci'
CreatePeopleDatasTable: alter table `people_datas` add primary key `people_datas_mt_id_valid_for_primary`(`mt_id`, `valid_for`)
CreatePeopleDatasTable: alter table `people_datas` add constraint `people_datas_valid_for_foreign` foreign key (`valid_for`) references `quarters` (`quarter_id`)
CreatePeopleDatasTable: alter table `people_datas` add constraint `people_datas_gender_foreign` foreign key (`gender`) references `genders` (`id`)
CreatePeopleDatasTable: alter table `people_datas` add constraint `people_datas_location_type_foreign` foreign key (`location_type`) references `location_types` (`id`)
CreatePeopleDatasTable: alter table `people_datas` add index `people_datas_last_name_index`(`last_name`)
Stratadox

对于第一个时间戳声明,MySql和/或MariaDB中时间戳默认值的默认行为与后续时间戳不同。

MariaDB对于在特定表中使用TIMESTAMP数据类型的第一列具有特殊的行为。对于在特定表中使用TIMESTAMP数据类型的第一列,MariaDB自动为该列分配以下属性:

在更新CURRENT_TIMESTAMP时默认CURRENT_TIMESTAMP

这意味着,如果未在INSERT或UPDATE查询中为该列显式分配一个值,那么MariaDB将自动使用当前日期和时间初始化该列的值。

通过为列指定DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP子句,还可以为使用TIMESTAMP数据类型的列显式启用INSERT和UPDATE查询的自动初始化。在这些条款中,将接受CURRENT_TIMESTAMP的任何同义词,包括CURRENT_TIMESTAMP(),NOW(),LOCALTIME,LOCALTIME(),LOCALTIMESTAMP和LOCALTIMESTAMP()。

https://mariadb.com/kb/zh/library/timestamp/

太好了,第一个时间戳(valid_from)会自动获得默认值CURRENT_TIMESTAMP,这是非空时间戳字段可接受的默认值。第二个字段获得一个不同的自动默认值,该值对于数据库似乎是不可接受的。

解决当前问题的方法可能是遵循MariaDB的建议,并CURRENT_TIMESTAMP在第二个时间戳(或同时使用两个时间戳)中使用显式默认值作为默认值。用Laravel来说,这可能类似于$table->timestamp('valid_to')->useCurrent();

在这方面需要注意的重要一点是,您最终选择的解决方案(使用datetime而不是timestamp)可能更适合解决该问题:timestamps是一些奇怪的数据类型,主要仅用作元数据。尤其是在Mysql和MariaDB中,它们固有地遭受“ 2038年问题”的困扰,这对于再过18年左右的created_at或updated_at字段来说不是问题,但是当valid_to可能是未来几年时可能会出现问题。这只是不直观的自动默认值的补充...

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在多个工作表中使用带有两个 IF 的时间戳?

在PHP(Laravel)中检查两个带有当前日期的时间戳

联接通过两个WITH语句创建的两个表时出现SQL错误-SQLite3

MySQL对两个表进行联合,其中一个带有时间戳,另一个带有日期

种子两个时间戳列的种子时,数据库迁移会引发错误laravel 5

使用来自其他两个表的数据创建表时出现 MySQL 语法错误

laravel carbon 从时间戳比较两个时区时间

找到带有时间戳的两个日期之间的分钟差异?

带有不同工作日的两个时间戳之间的差异?

合并两个带有时间戳和队列长度的元组列表

尝试使用条件逻辑针对两个现有日期列在 DataFrame 中创建新列时出现 Python 类型错误

使用带有两个参数的函数从两个现有列创建两个新列

bigquery 通过时间戳和另一列连接两个表

MySQL为表中的特定ID选择两个时间戳列之间的平均时差

SQL查询以合并两个具有不同时间戳的表作为索引

尝试在控制器中传递带有两个参数的命名路由时出现 500 内部错误

MySQL查询两个表和最大时间戳

在两个时间戳之间过滤数据透视表

SQL在时间戳上联接两个不同的表

带有时间戳错误的熊猫中的两个连续行之间的天数:dtype('<m8 [D]')

在pyspark中的两个时间戳之间创建一个时间戳数组

在带有两个选择列的Postgres(Redshift)中运行MAX聚合查询时出现问题

创建一个带有来自两个 SQL 表的标题的 HTML 表

减去AWS Athena中的两个时间戳列

如何找出两个熊猫时间戳之间的所有唯一时间?

如何创建带有增加的时间戳列的数据帧?

在PostgreSQL中,我们可以直接比较两个带有不同时区的时间戳吗?

打印两个时间戳之间的所有时间戳

带有两个列参数