2016-02-20 44 views
1

下面是我需要放置约束的模式,以便可以为房间号插入第二个新条目,甚至在同一房间号的现有depDt之前。你能帮助我吗?防止重叠日期范围的表级约束

CREATE TABLE Accomodation (
    roomNo INTEGER NOT NULL, 
    arrDt DATE NOT NULL, 
    depDt DATE NOT NULL, 
    PRIMARY KEY (roomNo, arrDt), 
    CONSTRAINT date_chk CHECK (arrDt < depDt) 
); 

INSERT INTO HotelStays(roomNo, arrDt, depDt) VALUES 
    (123, to_date('20160202', 'YYYYMMDD'),to_date('20160206','YYYYMMDD')), 
    (123, to_date('20160205', 'YYYYMMDD'), to_date('20160208','YYYYMMDD')); 

我试过在CONSTRAINTS的WHERE下给出一个子查询,但它不在SQL小提琴中工作。

+0

你在'INSERT'语句的第二个元素末尾缺少')'。 –

+0

对不起,但这是一个错字。 – Shashikiran

+0

从我看到的第二个条目中输入相同的房间号码__可以插入,只要他们的抵达日期不同。你真正的问题是什么?您能否显示预期的输出和错误或您收到的输出? –

回答

1

注意:这并不能解决竞争条件的问题。

创建一个函数,根据您的条件检查房间是否可用,并返回可在CHECK约束中使用的标量布尔值。

在这里,您可以预览它的工作原理(记得要取消对最后一个INSERT语句):SQL FIDDLE

CREATE FUNCTION is_room_available(int, date) 
RETURNS boolean 
STABLE 
LANGUAGE plpgsql 
AS 
$$ 
BEGIN 
    IF EXISTS (SELECT 1 FROM Accomodation WHERE roomNo = $1 AND $2 BETWEEN arrDt AND depDt) THEN 
    RETURN false; 
    END IF; 

    RETURN true; 
END; 
$$; 

与新的约束创建表

CREATE TABLE Accomodation (
    roomNo INTEGER NOT NULL, 
    arrDt DATE NOT NULL, 
    depDt DATE NOT NULL, 
    PRIMARY KEY (roomNo, arrDt), 
    CONSTRAINT date_chk CHECK (arrDt<depDt), 
    CONSTRAINT room_avail CHECK (is_room_available(roomNo, arrDt)) -- added 
); 

尝试在不同的语句

插入两行
INSERT INTO Accomodation(roomNo, arrDt, depDt) 
VALUES 
(123, to_date('20160202', 'YYYYMMDD'), to_date('20160206','YYYYMMDD')); 

INSERT INTO Accomodation(roomNo, arrDt, depDt) 
VALUES 
(123, to_date('20160205', 'YYYYMMDD'), to_date('20160208','YYYYMMDD')); 

第一个值被插入,而当发出第二插入语句,你得到检查约束违反

ERROR: new row for relation "accomodation" violates check constraint "room_avail" Detail: Failing row contains (123, 2016-02-05, 2016-02-08).

注意:这可以很容易地实现使用触发器为好。您只需稍微修改该功能并发出CREATE TRIGGER语句。

+0

$$是什么意思?你为什么使用GO终结者? – Shashikiran

+0

@Shashikiran:$$被称为美元报价:http://www.postgresql.org/docs/current/static/sql-syntax-lexical。html#SQL-SYNTAX-DOLLAR-QUOTING –

+0

@Shashikiran我在SQL Fiddle中使用GO作为终结符,以便能够在函数内使用';'而不会出错。通常情况下,这是终止符,并假设例如'END IF;'为无效语句就会产生错误。 –

2

这可以使用日期范围的exclusion constraint来完成:

alter table Accomodation 
    add constraint no_overlap 
    exclude using gist (roomno with =, daterange(arrdt, depdt) with &&); 

请注意,您所需要的btree_gist extension支持=运营商梗概指数。

+0

SQL小提琴没有这个扩展名。 – Shashikiran