Postgres 对年龄的约束

问题描述 投票:0回答:1

我对 Postgres 的范围类型有点陌生,我可以在以下方面寻求您的帮助:

一个人的出生日期和死亡日期需要记录在带有

daterange
的表格中。为了防止无效数据,我在表定义中添加了约束
alive_bounds

create table person (
  id bigserial not null,
  alive daterange not null,
  name text not null,
  constraint id_pkey primary key (id),
  constraint alive_bounds check (
    lower(alive) != 'infinity' and
    lower(alive) != '-infinity' and
    lower(alive) is not null and
    upper(alive) != 'infinity' and
    upper(alive) != '-infinity' and
    (coalesce(upper(alive), current_date)::timestamp
        - lower(alive)::timestamp) < interval '120 years'
  )
);
insert into person (alive, name) values (daterange(current_date, null), 'Some One');
insert into person (alive, name) values (daterange('1900-01-01', null), 'Another One');

输出:

INSERT 0 1
ERROR:  new row for relation "person" violates check constraint "alive_bounds"
DETAIL:  Failing row contains (2, [1900-01-01,), Another One).

除了文档中有关恢复数据并使用 trigger 的警告

之外,数据可能会随着时间的推移而损坏。例如,200 年内,ID 为 
1
 的人将会死亡。

为了测试 Postgres 如何处理这种情况,我重新创建了表,并将间隔设置为 1 秒。但是,当我再次插入 person

1

 时,Postgres 在间隔到期后不会给我任何警告,例如当我 
select
 数据时。

触发检查和此检查约束有什么区别? 有什么更好的解决方案来存储两个日期并让 Postgres 发出一些关于范围值无效或变得无效的警告?

postgresql range constraints
1个回答
0
投票
检查约束仅在修改行时进行检查,而不是在选择行时进行检查。 文档中的警告非常真实:如果转储数据库,稍后可能无法恢复转储。

什么是正确的做法取决于如果时间过去导致该行变得无效,您希望该行发生什么情况。

  • 如果您希望它从表中消失,唯一的选择是定期安排作业扫描表并删除所有无效行。

  • 如果您对行变得不可见感到满意,则可以使用行级安全策略将其从查询结果中排除:

    ALTER TABLE person ENABLE ROW LEVEL SECURITY; ALTER TABLE person FORCE ROW LEVEL SECURITY; CREATE POLICY vanish_old ON person FOR ALL TO PUBLIC USING (coalesce(upper(alive), current_date) - lower(alive) < 43830);
    行保留在表中,因此如果行数很多,这不是一个好的解决方案。

无论如何,消除有缺陷的检查约束。

© www.soinside.com 2019 - 2024. All rights reserved.