2013-04-09 68 views
0

我需要SQL Server中約束的幫助。情況是針對表上的每個OrderID = 1(外鍵不是主鍵,因此有多個具有相同ID的行),位字段對於其中一個行只能是1,對於OrderID = 2的每行,位字段對於一行只能是1等等。對於具有相同OrderID的所有其他行,它應該是0。如果已有一行OrderID具有位域設置爲1的任何新記錄,則在位域中以1進入的新記錄應拒絕。任何想法?SQL Server約束(基於外鍵的限制位字段)

+0

如果非答案適合您,尤其是在2008年以前的版本中,您可以編寫插入/更新觸發器來拒絕重複項 – Mark 2013-04-10 10:10:17

回答

1

你可以更完全地標準化模式,這將幫助你不必尋找已經設置的位,但使用連接。你需要刪除位字段並創建一個新的表,表示X包含OrderID和表的主鍵,X的主鍵是所有這些字段。

這意味着,當您插入時,您需要插入到原始表格和X f中,並且僅當您將該表格設置爲1時。如果X中已經有一行,就好像已經有一個原始行的位已設置爲1,則插入將失敗。

缺點是,這佔用了比您的模式更多的空間,但更容易維護爲您無法達到將該位設置爲1的兩行的等價物。

+0

如果必須更改表結構,我會牢記這一點。謝謝! – user2263882 2013-04-11 16:59:37

0

要做到這一點的唯一方法是對父表進行子類化。你沒有提到它,但是這種模式的一個常見原因是從具有相同公共鍵值的所有行集合中表示一個唯一的活動行。讓我們假設你的位字段表示活躍訂單.... 然後,我會創建一個名爲ActiveOrders一個單獨的表,其中只包含設置爲1

Create Table ActiveOrders(int Orderid Primary Key Null) 
位域一行

和其他表所有在它的行,與它自己唯一的主鍵的OrderId

Create Table AllOrders 
(OrderId Integer Primary Key Not Null, ActiveOrderId Integer Not Null, 
[All other data fields] 
Constraint FK_AllOrders2ActiveOrder 
    Foreign Key(ActiveOrderId) references ActiveOrders(OrderId)) 

您現在不再需要位域,因爲ActiveOrders表中的行的存在將其標識爲活動訂單...要僅獲取活動訂單(在您的方案中將位域設置的訂單到1),只需加入兩張表。

+0

謝謝,這是一個很好的建議。我暫時不想改變桌子的結構,但我會牢記這一點。 – user2263882 2013-04-11 16:58:33

0

我同意其他答案,如果你可以改變模式然後做,但如果沒有,那麼我認爲這樣的事情會做。

CREATE FUNCTION fnMyCheck 
    (@id INT) 
RETURNS INT 
AS 
BEGIN 
    DECLARE @i INT 

    SELECT @i = COUNT(*) 
    FROM MyTable 
    WHERE FkCol = @id 
    AND BitCol = 1 

    RETURN @i 
END 

ALTER TABLE YourTable 
ADD CONSTRAINT ckMyCheck CHECK (fnMyCheck(FkCol)<=1) 

,但也有可能來自使用檢查約束一個UDF做題,如this

編輯添加評論有關問題與本「解決方案」:

有比您所鏈接的更直接的問題。

INSERT INTO YourTable(FkCol,BitCol) VALUES (1,1),(1,0) 

其次

UPDATE YourTable SET BitCol=1 

成功,並留下兩排FkCol = 1和BitCol = 1

+1

有比您鏈接到的更直接的問題。在INSERT INTO YourTable(FkCol,BitCol)VALUES(1,1),(1,0)'後面加上'UPDATE YourTable SET BitCol = 1'成功並留下兩行,'FkCol' = 1且'BitCol' = 1 – 2013-04-10 06:47:29

2
CREATE UNIQUE INDEX ON UnnamedTable (OrderID) WHERE UnnamedBitField=1 

它被稱爲Filtered Index。如果您使用的是2008年之前的版本的SQL Server,你可以使用索引視圖實現過濾指數的差芒相當於:

CREATE VIEW UnnamedView 
WITH SCHEMABINDING 
AS 
    SELECT OrderID From UnnamedSchema.UnnamedTable WHERE UnnamedBitField=1 
GO 
CREATE UNIQUE CLUSTERED INDEX ON UnnamedView (OrderID) 

你不能真正做到這一點作爲一個約束,因爲SQL Server僅支持列約束和行約束。沒有(非欺騙性)的方式來編寫處理表中所有值的約束。

+0

我正在使用SQL Server 2000(難過,我知道),所以我使用了索引視圖,這對我很有用。唯一的區別是我不得不使用「CREATE UNIQUE CLUSTERED INDEX」而不是「CREATE UNIQUE INDEX」。謝謝! – user2263882 2013-04-11 16:53:21

+0

@ user2263882 - 我已經更新了樣本(我承認,我沒有必要使用這些努力多年並從內存中工作)。 – 2013-04-11 17:03:11