【问题标题】:postgresql unique index preventing overlapingpostgresql唯一索引防止重叠
【发布时间】:2019-04-11 02:22:25
【问题描述】:

我的表权限如下:

id serial,
person_id integer,
permission_id integer,
valid_from date,
valid_to date

我想防止创建与 valid_from、valid_to 日期重叠的权限

例如。

1 | 1 | 1 | 2010-10-01 | 2999-12-31
2 | 1 | 2 | 2010-10-01 | 2020-12-31
3 | 2 | 1 | 2015-10-01 | 2999-12-31

这个可以加:

4 | 1 | 3 | 2011-10-01 | 2999-12-31 - because no such permission
5 | 2 | 1 | 2011-10-10 | 2999-12-31 - because no such person
6 | 1 | 2 | 2021-01-01 | 2999-12-31 - because doesn't overlaps id:2

但这不能

7 | 1 | 1 | 2009-10-01 | 2010-02-01 - because overlaps id:1
8 | 1 | 2 | 2019-01-01 | 2022-12-31 - because overlaps id:2
9 | 2 | 1 | 2010-01-01 | 2016-12-31 - beacuse overlaps id:3

我可以进行外部检查,但想知道是否可以在数据库上进行检查

【问题讨论】:

    标签: postgresql indexing constraints unique


    【解决方案1】:

    唯一约束基于相等运算符,在这种情况下不能使用,但您可以使用exclude constraint. 该约束使用 btree 运算符 <>=,因此您必须安装 btree_gist extension.

    create extension if not exists btree_gist;
    
    create table permission(
        id serial,
        person_id integer,
        permission_id integer,
        valid_from date,
        valid_to date,
        exclude using gist (
            person_id with =, 
            permission_id with =, 
            daterange(valid_from, valid_to) with &&)
    );
    

    这些插入成功:

    insert into permission values
        (1, 1, 1, '2010-10-01', '2999-12-31'),
        (2, 1, 2, '2010-10-01', '2020-12-31'),
        (3, 2, 1, '2015-10-01', '2999-12-31'),
        (4, 1, 3, '2011-10-01', '2999-12-31'),
        (5, 3, 1, '2011-10-10', '2999-12-31'), -- you meant person_id = 3 I suppose
        (6, 1, 2, '2021-01-01', '2999-12-31'),
        (7, 1, 1, '2009-10-01', '2010-02-01'); -- ranges do not overlap!
    

    但这个不是:

    insert into permission values
        (8, 1, 2, '2019-01-01', '2022-12-31');
    
    ERROR:  conflicting key value violates exclusion constraint "permission_person_id_permission_id_daterange_excl"
    DETAIL:  Key (person_id, permission_id, daterange(valid_from, valid_to))=(1, 2, [2019-01-01,2022-12-31)) conflicts with existing key (person_id, permission_id, daterange(valid_from, valid_to))=(1, 2, [2010-10-01,2020-12-31)).
    

    db<>fiddle.试试吧

    【讨论】:

    • 完美解决方案!现在我有时间做一个测试——这正是我需要的。我想,我应该为每个数据库做一次create extension if not exists btree_gist;
    • 是的,扩展程序应该在您需要的数据库中安装一次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-02
    • 1970-01-01
    • 2020-10-01
    • 2015-04-24
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多