2012-04-09 50 views
1

這是我的玩具設置。我有3張桌子。一張桌子是客人名單(姓,名,無論),食物清單(豆,糊,米,蔬菜)和訂單清單(客人ID,食物ID)。訂單清單是我感興趣的。我想限制它的以下條件。如何在Oracle中創建這個約束無需PL/SQL

客人必須有3個訂單。 客人可以有空訂單。 每位客人的訂單不能相同,除非訂單爲空。

因此,爲了表將如下所示(用繩子代替FK IDS):

steve, beans 
steve, rice 
steve, veggies 
joey, rice 
joey, beans 
joey, <null> 
sarah, rice 
sarah, <null> 
sarah, <null> 
sam, <null> 
sam, <null> 
sam, <null> 

顯然薩姆不喜歡的食物...但是這將是一個有效的表。每個用戶有3個條目,並且沒有用戶有重複(沒有雙重豆給你!)。

事情我已經試過

create table order (
    guest_uid FK, 
    food_uid FK, 
    CONSTRAINT order_unique UNIQUE (guest_uid, food_uid) 
) 

這工作得很好驗證沒有雙豆,但雙/三零不會飛。我希望oracle獨特的null在這裏適用,但我想不是(違反唯一約束order_unique)。

我嘗試了一些其他的檢查約束,但我找不到一個方法來指定跨行的唯一性,而不做子查詢(當然這是不允許的)。有什麼想法嗎?謝謝

ps。如果唯一有效的答案是「使用PL/SQL或觸發器」,我將確保標記出正確的答案。

回答

4

可以使用基於函數的索引來強制跨行獨特性(注意,我叫表guest_food因爲order是保留字

create unique index idx_order_unique 
    on guest_food(case when food_uid is not null 
         then guest_uid 
         else null 
        end, 
        case when food_uid is not null 
         then food_uid 
         else null 
        end); 

這將讓你有一個儘可能多的行NULLfood_uid針對任何特定guest_uid同時禁止複製非NULL值。

每一位客人都有在guest_food表正是三行的要求是不是你可以使用約束強制執行。ÿ ou可能會創建一個物化視圖,該視圖對提交進行快速刷新,該刷新存儲每個guest_uid的行數,並添加一個約束,如果該計數不是3,則會引發錯誤。但這通常是一種非常不尋常的事情想要執行,所以它會讓我懷疑數據模型有點不合適。

+0

雙雙哦!我認爲聯邦調查局不贊成。即使我的玩具例子使用了一個保留字。 Oooffff。謝謝你的幫助。 – howsyouredge 2012-04-09 19:56:54

1

您是否考慮過更改數據結構?既然你有順序正好三個項目,轉動的項目:

create table order 
(
    guest_uid FK, 
    food_uid1 FK, 
    food_uid2 FK, 
    food_uid3 FK 
) 

然後,您可以爲每個food_uid添加約束,以確保外鍵是正確的。

然後,您可以添加一個檢查約束來滿足除NULL之外沒有重複的要求。

+1

當用戶不可避免地改變他們對訂單中有多少食物的想法時會發生什麼?當你想用扁豆代替豆時會發生什麼 - 你最終不得不更新所有三列。其他很多例子都說明了爲什麼這不是處理這些情況的最佳方式。 – 2012-04-09 20:31:16

+0

我同意邁克瑞恩。這不是我想要的方式。事實上,3規則已經改變...... – howsyouredge 2012-04-10 13:32:01