我有一个date
列,我想在填充后保持唯一,但如果未填充date
字段,则希望忽略该字段。
在MySQL中,完成此操作的方法是将date
列设置为“not null”并为其指定默认值'0000-00-00' - 这允许唯一索引中的所有其他字段即使尚未填充date
列,也要“检查”。
这在PosgreSQL中不起作用因为'0000-00-00'不是有效日期,所以你不能将它存储在日期字段中(这对我来说很有意义)。
乍一看,离开字段nullable
似乎是一种选择,但这会产生问题:
=> create table uniq_test(NUMBER bigint not null, date DATE, UNIQUE(number, date));
CREATE TABLE
=> insert into uniq_test(number) values(1);
INSERT 0 1
=> insert into uniq_test(number) values(1);
INSERT 0 1
=> insert into uniq_test(number) values(1);
INSERT 0 1
=> insert into uniq_test(number) values(1);
INSERT 0 1
=> select * from uniq_test;
number | date
--------+------
1 |
1 |
1 |
1 |
(4 rows)
NULL显然“不等于它自己”,所以它不计入约束。
如果我仅在number
字段上添加其他唯一约束,则仅检查number
而不是date
,因此我不能拥有两个具有不同日期的数字。
我可以选择一个“有效日期”(但在工作范围之外)的默认日期来解决这个问题,并且可以(实际上)为当前项目侥幸逃脱,但实际上我可能会遇到这种情况。在接下来的几年中遇到这样的事实并非显而易见,因为它是“很久以前”或“未来”,日期是非实际日期。
'0000-00-00'机制对我的好处恰恰在于这个日期不是真实的,因此表示一个非填充的条目(其中'非填充'是有效的唯一性属性)。当我在互联网上四处寻找解决方案时,我发现的大部分内容都是“只使用NULL”,“存储零是愚蠢的。”
TL; DR 是否存在PostgreSQL最佳做法,需要在包含日期字段的唯一约束中包含“未填充”作为可能的值?
答案 0 :(得分:2)
不清楚你想要什么。这是我的猜测:
create table uniq_test (number bigint not null, date date);
create unique index i1 on uniq_test (number, date)
where date is not null;
create unique index i2 on uniq_test (number)
where date is null;
对于非空日期将存在唯一约束,对于空日期将存在另一个约束,从而有效地将(number, date)
元组转换为不同的值。
答案 1 :(得分:0)
这不是最佳做法,但你可以这样做:
t=# create table so35(i int, d date);
CREATE TABLE
t=# create unique index i35 on so35(i, coalesce(d,'-infinity'));
CREATE INDEX
t=# insert into so35 (i) select 1;
INSERT 0 1
t=# insert into so35 (i) select 2;
INSERT 0 1
t=# insert into so35 (i) select 2;
ERROR: duplicate key value violates unique constraint "i35"
DETAIL: Key (i, (COALESCE(d, '-infinity'::date)))=(2, -infinity) already exists.
STATEMENT: insert into so35 (i) select 2;