防止日期重叠的SQL检查约束

防止日期重叠的SQL检查约束,sql,postgresql,constraints,date-range,Sql,Postgresql,Constraints,Date Range,我有一个表格,描述了在不同时间在机器上安装的软件版本: machine_id::integer, version::text, datefrom::timestamp, dateto::timestamp 我想做一个约束,以确保没有日期范围重叠,即不可能在一台机器上同时安装多个软件版本 如何在SQL中实现这一点?我使用的是PostgreSQL v8.4。您真的想要像标题中提到的那样检查成本吗?这是不可能的,因为检查约束一次只能工作一行。也许有一种方法可以使用触发器来实现这一点,但是在Postg

我有一个表格,描述了在不同时间在机器上安装的软件版本:

machine_id::integer, version::text, datefrom::timestamp, dateto::timestamp
我想做一个约束,以确保没有日期范围重叠,即不可能在一台机器上同时安装多个软件版本


如何在SQL中实现这一点?我使用的是PostgreSQL v8.4。

您真的想要像标题中提到的那样检查成本吗?这是不可能的,因为检查约束一次只能工作一行。也许有一种方法可以使用触发器来实现这一点,但是在PostgreSQL 8.4中,这只能通过触发器来解决。触发器必须在插入/更新时检查是否不存在冲突行。因为事务可序列化性没有实现谓词锁定,所以您必须自己执行必要的锁定。要执行此操作,请选择更新machines表中的行,以便其他事务不能同时插入可能冲突的数据


在PostgreSQL 9.0中,将有一个更好的解决方案,称为排除约束,在下面有一些文档记录。这将允许您指定日期范围不得重叠的约束。杰夫·戴维斯(Jeff Davis)是这篇专题文章的作者,他对这篇文章有两部分的评论:。Depesz也有一些。

同时,从9.2版开始,如果我正确阅读手册,postgreSQL增加了对的支持

对于这些rangetypes,问题突然变得非常简单,例如,从手册中复制:

CREATE TABLE reservation (
    during tsrange,
    EXCLUDE USING gist (during WITH &&)
);
INSERT INTO reservation VALUES
    ('[2010-01-01 11:30, 2010-01-01 15:00)');
就这样。测试也从手册中复制:

CREATE TABLE reservation (
    during tsrange,
    EXCLUDE USING gist (during WITH &&)
);
INSERT INTO reservation VALUES
    ('[2010-01-01 11:30, 2010-01-01 15:00)');
插入0 1

错误:冲突的键值在\u excl期间违反了排除约束保留\u 详细信息:按键期间=[2010-01-01 14:45:002010-01-01 15:45:00冲突 使用期间的现有密钥=[2010-01-01 11:30:002010-01-01 15:00:00


如果出于某种原因无法更改表架构,并且需要保留两个时间行,则可以在约束内构建范围,例如:

创建表格预订 datefrom时间戳, 日期到时间戳, 使用gist tsrangedatefrom、dateto和排除&& ; 在本例中,我使用了tsrange来处理时间戳类型,但是您还可以使用其他类型的时间戳-请查看位于的文档


表中具有相同id的计算机不会重叠。

任何约束数据的方法都是足够的。我只是错了!假设这是一个检查…您将如何让此EXCLUDE语句用于具有FK的唯一行,即我们有一个CREATE table RESERVICE resourceId integer not NULL,在tsrange期间,EXCLUDE使用gist-during WITH&&;@mikejames:Like this:使用gist-resourceId WITH=,during WITH&&to使用exclude WITH标量值启用:创建扩展名btree_-gist;然后,使用gist-resourceId WITH=,during WITH排除&&
CREATE EXTENSION IF NOT EXISTS btree_gist; 

CREATE TABLE machines(
    machine_id integer, 
    version text, 
    during tsrange,
    EXCLUDE USING gist ( machine_id with =, during with &&)
);