2016-04-29 298 views
3

我想解決這個問題(應該是可以解決的)。 您有下表。該表包括座位預留,保留了開始/結束日期之間的所有座位。用subquerys檢查Oracle的限制[exercise]

CREATE TABLE reservation ( 
    owner CHAR(10) NOT NULL PRIMARY KEY, 
    start INTEGER NOT NULL, 
    end INTEGER NOT NULL 
) 

擴展這個表定義與約束什麼檢查,沒有哪個地方會被保留兩次。

據我所知,在檢查約束中不可能使用子查詢。那麼我可以使用什麼樣的約束?

+1

,可以使用約束無法做到這一點。你需要一個trigger.stackoverflow.com/questions/8770552/can-i-have-a-constraint-on-count-of-distinct-values-in-a-column-in-sql –

+0

是的,這就是我所知道的,但我想知道這是否可能。 –

+0

你可以改變表格(添加更多列等)嗎?如果是,那麼是的,這是可能的。通過單獨的DRI(FOREIGN KEY,UNIQUE和CHECK約束)使複雜但可能。 –

回答

3

這不能用單個CHECK約束來完成,因爲它本質上是一個依賴表的多個行的約束。

它與某種方式的UNIQUE約束相似。在唯一約束中,沒有兩行可以具有相同的值。在這裏,沒有兩行可以有重疊範圍。所以,如果我們能夠用檢查重疊範圍的條件替換平等條件(=),那就恰到好處。

在另一個DBMS(Postgres)中,實際上可以使用專有的EXCLUDE約束強制執行這個和類似的約束。


在Oracle現在有共同的FOREIGN KEYUNIQUECHECK限制其他DBMS,它實際上是可能的,但複雜的,如果你被允許加入另一列更改表設計:

CREATE TABLE reservation ( 
    owner CHAR(10) NOT NULL PRIMARY KEY, 
    start INTEGER NOT NULL, 
    end INTEGER NOT NULL, 
    previous_end INTEGER NULL, 

    CONSTRAINT valid_range 
     CHECK (start <= end), 
    CONSTRAINT unique_end 
     UNIQUE (end), 
    CONSTRAINT previous_range_fk 
     FOREIGN KEY (previous_end) 
     REFERENCES reservation (end), 
    CONSTRAINT valid_previous 
     CHECK (previous_end < start) 
) ; 

我們很好去。你只需要正確地提供previous_end的值,從本質上使該表成爲一個鏈表。所有限制條件一起工作以確保範圍不重疊。

+0

其實我認爲它也需要'UNIQUE(previous_end)'約束。我會引導並糾正。 –

0

可以使用物化視圖解決這個問題:據我所知

CREATE TABLE reservation ( 
    owner CHAR(10) NOT NULL PRIMARY KEY, 
    "start" INTEGER NOT NULL, 
    "end" INTEGER NOT NULL 
); 

CREATE MATERIALIZED VIEW LOG ON reservation 
    WITH SEQUENCE, ROWID("start","end") 
    INCLUDING NEW VALUES; 

CREATE MATERIALIZED VIEW reservation_MV 
    BUILD IMMEDIATE 
    REFRESH FAST ON COMMIT 
    AS SELECT "start" + LEVEL - 1 AS table_number 
     FROM reservation 
     CONNECT BY "start" + LEVEL - 1 <= "end"; 

ALTER TABLE reservation_MV ADD CONSTRAINT reservation__mv__pk 
    PRIMARY KEY (table_number);