Laravel 创建具有两个时间戳列的 table 时出错
Laravel error in creating a table with two timestamp columns
我在 Laravel 6.6 中创建了一个具有以下定义的 table。
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]: Syntax error or
access violation: 1067 Invalid default value for 'valid_to' (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')
这里是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'
st运行ge 的事情是,如果我注释掉 valid_to
行,那么它会创建 table 而没有错误。但是 valid_to
的定义与 valid_from
的定义 100% 相似,并且它不会为 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`)
我通过将列的类型从 timestamp
更改为 dateTime
解决了我的问题。因此,如下更改 table 定义解决了我的问题,因为我需要日期和时间:
Schema::create('quarters', function (Blueprint $table) {
$table->integer('quarter_id')->unsigned();
$table->integer('year')->unsigned();
$table->integer('quarter_num')->unsigned();
$table->dateTime('valid_from');
$table->dateTime('valid_to');
$table->string('description')->nullable();
$table->timestamps();
$table->primary('quarter_id');
});
但是,我仍然很想知道如何在 table 中包含多个 not null
时间戳列。
MySql and/or MariaDB 中时间戳默认值的默认行为对于第一个时间戳声明与后续时间戳不同。
MariaDB has special behavior for the first column that uses the TIMESTAMP data type in a specific table. For the first column that uses the TIMESTAMP data type in a specific table, MariaDB automatically assigns the following properties to the column:
DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
This means that if the column is not explicitly assigned a value in an INSERT or UPDATE query, then MariaDB will automatically initialize the column's value with the current date and time.
This automatic initialization for INSERT and UPDATE queries can also be explicitly enabled for a column that uses the TIMESTAMP data type by specifying the DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP clauses for the column. In these clauses, any synonym of CURRENT_TIMESTAMP is accepted, including CURRENT_TIMESTAMP(), NOW(), LOCALTIME, LOCALTIME(), LOCALTIMESTAMP, and LOCALTIMESTAMP().
https://mariadb.com/kb/en/library/timestamp/
因此,第一个时间戳 (valid_from
) 获得自动默认值 CURRENT_TIMESTAMP
,这是不可为 null 的时间戳字段可接受的默认值。第二个字段获得不同的自动默认值,这似乎是数据库无法接受的。
解决当前问题的方法可能是遵循 MariaDB 的建议,并使用显式 CURRENT_TIMESTAMP
作为第二个时间戳的默认值(或两者同时使用)。
在 Laravel 术语中,这可能类似于 $table->timestamp('valid_to')->useCurrent();
。
在这方面需要注意的重要一点是,您最终选择的解决方案(使用日期时间而不是时间戳)可能是解决该问题的更合适的解决方案:时间戳是一些奇怪的数据类型,主要用于仅作为元数据。尤其是在 Mysql 和 MariaDB 中,它们天生就受到 "Year 2038 problem" 的影响,这对于 created_at 或 updated_at 字段来说再过 18 年左右都不是问题,但可能是当 valid_to 可能是几年后的时候会出现问题。这只是不直观的自动默认值的补充...
我在 Laravel 6.6 中创建了一个具有以下定义的 table。
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]: Syntax error or access violation: 1067 Invalid default value for 'valid_to' (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')
这里是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'
st运行ge 的事情是,如果我注释掉 valid_to
行,那么它会创建 table 而没有错误。但是 valid_to
的定义与 valid_from
的定义 100% 相似,并且它不会为 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`)
我通过将列的类型从 timestamp
更改为 dateTime
解决了我的问题。因此,如下更改 table 定义解决了我的问题,因为我需要日期和时间:
Schema::create('quarters', function (Blueprint $table) {
$table->integer('quarter_id')->unsigned();
$table->integer('year')->unsigned();
$table->integer('quarter_num')->unsigned();
$table->dateTime('valid_from');
$table->dateTime('valid_to');
$table->string('description')->nullable();
$table->timestamps();
$table->primary('quarter_id');
});
但是,我仍然很想知道如何在 table 中包含多个 not null
时间戳列。
MySql and/or MariaDB 中时间戳默认值的默认行为对于第一个时间戳声明与后续时间戳不同。
MariaDB has special behavior for the first column that uses the TIMESTAMP data type in a specific table. For the first column that uses the TIMESTAMP data type in a specific table, MariaDB automatically assigns the following properties to the column:
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
This means that if the column is not explicitly assigned a value in an INSERT or UPDATE query, then MariaDB will automatically initialize the column's value with the current date and time.
This automatic initialization for INSERT and UPDATE queries can also be explicitly enabled for a column that uses the TIMESTAMP data type by specifying the DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP clauses for the column. In these clauses, any synonym of CURRENT_TIMESTAMP is accepted, including CURRENT_TIMESTAMP(), NOW(), LOCALTIME, LOCALTIME(), LOCALTIMESTAMP, and LOCALTIMESTAMP().
https://mariadb.com/kb/en/library/timestamp/
因此,第一个时间戳 (valid_from
) 获得自动默认值 CURRENT_TIMESTAMP
,这是不可为 null 的时间戳字段可接受的默认值。第二个字段获得不同的自动默认值,这似乎是数据库无法接受的。
解决当前问题的方法可能是遵循 MariaDB 的建议,并使用显式 CURRENT_TIMESTAMP
作为第二个时间戳的默认值(或两者同时使用)。
在 Laravel 术语中,这可能类似于 $table->timestamp('valid_to')->useCurrent();
。
在这方面需要注意的重要一点是,您最终选择的解决方案(使用日期时间而不是时间戳)可能是解决该问题的更合适的解决方案:时间戳是一些奇怪的数据类型,主要用于仅作为元数据。尤其是在 Mysql 和 MariaDB 中,它们天生就受到 "Year 2038 problem" 的影响,这对于 created_at 或 updated_at 字段来说再过 18 年左右都不是问题,但可能是当 valid_to 可能是几年后的时候会出现问题。这只是不直观的自动默认值的补充...