【发布时间】:2019-06-19 05:02:53
【问题描述】:
我创建了一个触发器来为购买设置一个 uniq 名称 (ref),使用时区作为 create_date 字段。 它工作正常,直到我注意到重复的引用,其中一个引用的引用中的日期与 create_date 字段中的日期不匹配(差异的 1 天)?!!
BEGIN
SET NEW.reference := concat(
(SELECT name FROM provider WHERE id = NEW.provider_id),
date_format(NEW.create_date, '%Y%m%d'), '/',
(SELECT LPAD(IFNULL(MAX(SUBSTRING_INDEX(reference, '/', -1)) + 1, 0), 3, '0')
FROM purchase
WHERE date_format(NEW.create_date, '%Y%m%d') = date_format(create_date, '%Y%m%d')
AND NEW.provider_id = provider_id
)
);
END
有人知道发生了什么或更好的方法吗?
PS:create_date 字段中的日期是正确的,ref 中使用的 NEW.create_date 中的日期是错误的(可能是客户端时区的 b/c,因为我们将其作为字符串发送)
更新
表格结构:
购买:
CREATE TABLE purchase
(
id int auto_increment primary key,
provider_id int not null,
create_date timestamp null,
create_user int null,
change_date timestamp null,
change_user int null,
group_id int null,
reference varchar(45) null
);
CREATE INDEX purchase_reference_index ON purchase (reference);
CREATE INDEX purchase_provider_index ON purchase (provider_id);
提供者:
CREATE TABLE provider
(
id int auto_increment primary key,
name varchar(45) null,
constraint name_uniq unique (name)
);
查询示例:
INSERT INTO purchase (provider_id, create_date, create_user, group_id)
VALUE (4, '2019-01-30 02:36:58', 1, 3);
当我从使用服务器时区的会话中选择2019-01-29 23:36:58 时,2019-01-30 02:36:58 在数据库中保存为2019-01-29 23:36:58。
我用来设置时区的函数:
function update_timezone($timezone = null)
{
if (is_null($timezone)) $timezone = __SERVER_TIMEZONE;
if (in_array($timezone, timezone_identifiers_list())) {
date_default_timezone_set($timezone);
$tz = (new DateTime('now', new DateTimeZone(date_default_timezone_get())))->format('P');
$conn = Database::Connect();
Database::NonQuery("SET time_zone = '$tz';", $conn);
}
}
我的期望:
reference === 'provider_name20190129/00X'
我得到了什么:
reference === 'provider_name20190130/00Y'
如何重现问题:
CREATE DATABASE test;
CREATE TABLE purchase
(
id int auto_increment primary key,
provider_id int not null,
create_date timestamp null,
create_user int null,
change_date timestamp null,
change_user int null,
group_id int null,
reference varchar(45) null
);
CREATE INDEX purchase_reference_index ON purchase (reference);
CREATE INDEX purchase_provider_index ON purchase (provider_id);
CREATE TABLE provider
(
id int auto_increment primary key,
name varchar(45) null,
constraint name_uniq unique (name)
);
CREATE TRIGGER test.purchase_ref_insert
BEFORE INSERT
ON test.purchase
FOR EACH ROW
BEGIN
SET NEW.reference := concat(
(SELECT name FROM provider WHERE id = NEW.provider_id),
date_format(NEW.create_date, '%Y%m%d'), '/',
(SELECT LPAD(IFNULL(MAX(SUBSTRING_INDEX(reference, '/', -1)) + 1, 0), 3, '0')
FROM purchase
WHERE date_format(NEW.create_date, '%Y%m%d') = date_format(create_date, '%Y%m%d')
AND NEW.provider_id = provider_id
)
);
END
;
INSERT INTO provider (name) VALUE ('test');
SET time_zone = '+00:00';
INSERT INTO purchase (provider_id, create_date, create_user, group_id)
VALUE (1, '2019-01-30 02:36:58', 1, 3);
SET time_zone = '+05:00';
INSERT INTO purchase (provider_id, create_date, create_user, group_id)
VALUE (1, '2019-01-30 02:36:58', 1, 3);
SET time_zone = '-05:00';
INSERT INTO purchase (provider_id, create_date, create_user, group_id)
VALUE (1, '2019-01-30 02:36:58', 1, 3);
SET time_zone = '+00:00';
SELECT create_date, reference FROM purchase;
这是我得到的:
【问题讨论】:
-
表结构和数据在这里会有所帮助
-
考虑使用
TIMESTAMP而不是DATETIME。并确保每台计算机都设置了适当的时区。 -
@RaymondNijland 我更新了问题,请再看看
-
@RickJames 我正在使用 DATATIME 并切换到 TIMESTAMP(当客户想要使用不同的时区时,我的问题就开始了)
标签: mysql triggers timezone mariadb