2016-02-20 72 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