POSTGRES - 插入只有某些栏填写
问题描述:
ID start_date end_date account
1 2016-06-30 null 123
1 2017-04-19 null 111
1 2017-04-26 2017-07-30 789
想完成:
有没有一种方法来创建一个约束/索引/其他机制,检查:
- 如果存在ID和帐户和结束日期为空 - >无能为力
- 如果存在ID和帐户和结束日期不为空 - >插入行
所以:
insert into table (ID, start_date, account) values (1,2016-08-01,123)
- >什么也没有发生
insert into table (ID, start_date, account) values (1,2017-04-26, 789)
- >插入行
我在想也许CHECK约束与存储函数,将威尔我检查上述或类似的东西?或指数:
create unique index unique_account on table (ID, account) where end_date is null
答
这是最好的做法
警告:使用触发器在高交易数据库会导致性能问题。
解决方案:我假设你使用PostgreSQL 9.5或以上
直到这一步,你几乎已经完成
create unique index unique_account on table (ID, account) where end_date is null
所有你必须在PostgreSQL的9.5或以上使用UPSERT
查询做
ANS CASE 1:
Insert into insert_only (ID, start_date, account) values (1,'2016-08-01',123) ON CONFLICT DO NOTHING;
*我们需要"CONFLICT"
的唯一索引。这个查询意味着如果你插入相同的id + acoount + date is null
然后"ON CONFLICT"
将执行和DO NOTHING
。
ANS案例2:
Insert into insert_only (ID, start_date, end_date,account) values (1,'2016-08-01','2016-08-01',789) ON CONFLICT DO NOTHING;
*使用相同的查询,我们输入end_date
值是考虑789
插入会成功。
OUTPUT:
BEFORE:
stackoverflow=# select * from insert_only;
id | start_date | end_date | account
----+------------+------------+---------
1 | 2016-08-01 | | 123
1 | 2017-08-01 | | 111
1 | 2017-04-26 | 2017-07-30 | 789
1 | 2016-08-01 | 2016-08-01 | 789
(4 rows)
stackoverflow=# Insert into insert_only (ID, start_date, account) values (1,'2016-08-01',123) ON CONFLICT DO NOTHING;
INSERT 0 0
stackoverflow=# Insert into insert_only (ID, start_date, end_date,account) values (1,'2016-08-01','2016-08-01',789) ON CONFLICT DO NOTHING;
INSERT 0 1
AFTER:
stackoverflow=# select * from insert_only;
id | start_date | end_date | account
----+------------+------------+---------
1 | 2016-08-01 | | 123
1 | 2017-08-01 | | 111
1 | 2017-04-26 | 2017-07-30 | 789
1 | 2016-08-01 | 2016-08-01 | 789
1 | 2016-08-01 | 2016-08-01 | 789
(5 rows)
+1
希望这个解决方案可以帮助你。并且从不在插入时使用触发器来验证这会在将来数据增长为100万时造成麻烦。 –
您可以通过包装INSERT INTO存储过程实现这一目标。然后拒绝对该表的写入权限。因此,所有的写作都必须通过应用所有必要检查的程序。哦,但你已经在想这个了。 –
我觉得你实际上想要一个强制实现非重叠日期范围的约束(per {id,account})在这种情况下,对于* open *区间使用'+ infinity'会比NULL更实用。 – wildplasser