2011-11-02 42 views
4

我使用SQL Server 2008中我有一個數據庫表,看起來像這樣(與不重要列ommitted):SQL服務器過濾索引唯一約束

CREATE TABLE [dbo].[ImageDocument_FaxProperties](
    [FaxPropertyID] [int] PRIMARY KEY IDENTITY(1,1), 
    [Agent] [varchar](25) NULL, 
    [ParentImageDocumentId] [uniqueidentifier] NULL 
) 

我想創建一個約束,其中相同只要ParentImageDocumentIds在每一行上相同,代理就可以有多行,但代理不能有具有不同ParentImageDocumentIds的行。我知道這不是一個好的表格結構,但它的傳統&我不允許改變它。 NULL ParentImageDocumentIds應該被認爲是不同的。

例如:

PK Agent  ParentImageDocumentId -This is ok 
# person1 {D09C3900-0300}  {.. other columns ..} 
# person1 {D09C3900-0300}  {.. other columns ..} 

PK Agent  ParentImageDocumentId -Check constraint prevents 2nd row insertion 
# person1 NULL     {.. other columns ..} 
# person1 NULL     {.. other columns ..} 

PK Agent  ParentImageDocumentId -Check constraint prevents 2nd row insertion 
# person1 NULL     {.. other columns ..} 
# person1 {A13E5B21-93DE}  {.. other columns ..} 

PK Agent  ParentImageDocumentId -Check constraint prevents 2nd row insertion 
# person1 {D09C3900-0300}  {.. other columns ..} 
# person1 {A13E5B21-93DE}  {.. other columns ..} 

我不知道什麼是寫這個約束的最佳途徑。代理商的獨特索引不起作用,因爲它們有時可以兼得。一個獨特的Agent,ParentImageDocumentId將允許他們擁有不同的GUID,這是不好的。具有「WHERE ParentImageDocumentId IS NULL AND Agent IS NOT NULL」的篩選索引將用於防止出現雙重NULL,但不能使用不同的GUID或NULL。

下面是兩個工作解決方案,但我想知道是否有更好的方法。索引模式綁定視圖允許我創建更復雜的過濾索引。另一種方法是使用函數的表級檢查約束,這應該可行,但添加檢查約束是超慢。我猜它正在爲表中的每一行重新運行我的函數,但添加一個表級約束是不必要的,因爲函數沒有檢查特定的行。有沒有解決的辦法?我傾向於索引視圖,但想知道是否有替代方案(除了更改我的表結構)&哪個替代方案是最好的。

解決方案#1:

CREATE VIEW ImageDocument_FaxProperties_Assignments WITH SCHEMABINDING 
AS 
    SELECT Agent, ParentImageDocumentId, COUNT_BIG(*) as numPages FROM dbo.ImageDocument_FaxProperties 
    WHERE Status IN ('PROC', 'LINKING') 
    AND Agent IS NOT NULL 
    GROUP BY Agent, ParentImageDocumentId 
GO 

CREATE UNIQUE CLUSTERED INDEX [IDX_ImageDocument_FaxProperties_Assignments_Unique] ON [ImageDocument_FaxProperties_Assignments] (Agent) 
GO 

解決方案2:

CREATE FUNCTION ImageDocument_FaxProperties_Assignments_CheckConstraint() RETURNS BIT 
AS 
BEGIN 
    DECLARE @Result BIT = 0; 
    WITH Assignments AS 
    (SELECT Agent, DENSE_RANK() OVER (PARTITION BY Agent ORDER BY ParentImageDocumentId) AS assignmentNum 
    FROM dbo.ImageDocument_FaxProperties 
    WHERE Status IN ('PROC', 'LINKING') 
    AND Agent IS NOT NULL 
    ) 

    SELECT @Result = 1 FROM Assignments WHERE assignmentNum > 1 

    RETURN @Result 
END 
GO 
ALTER TABLE [ImageDocument_FaxProperties] 
ADD CONSTRAINT ImageDocument_FaxProperties_Assignments_Unique CHECK (dbo.ImageDocument_FaxProperties_Assignments_CheckConstraint() = 0) 
+0

FWIW,基於udf的解決方案導致我頻繁死鎖。過濾視圖效果更好。 – Constantin

回答

1

你的另一種選擇是一個觸發器添加到基表來檢查任何數據增加或修改符合規定的規則。

+0

我想我沒有想到這一點,因爲我工作中的人談論觸發器就像他們是一個骯髒的詞,但你是對的,這也會起作用。謝謝。 –