SQL Server筛选的唯一约束索引

时间:2011-11-02 23:19:28

标签: sql-server

我正在使用SQL Server 2008.我有一个看起来像这样的数据库表(省略了不重要的列):

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

我想创建一个约束,其中同一个代理可以有多行,只要每行的ParentImageDocumentId相同,但代理不能包含具有不同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上的唯一索引不起作用,因为它们有时可以同时使用。 Agent上的唯一,ParentImageDocumentId将允许它们具有不同的GUID,这是不正常的。带有“WHERE ParentImageDocumentId IS NULL AND Agent IS NOT NULL”的过滤索引将用于防止双重NULL,但不能防止不同的GUID或GUID& NULL。

下面是两个有效的解决方案,但我想知道是否有更好的方法。索引的模式绑定视图允许我创建更复杂的过滤索引。另一种方法是使用函数的表级检查约束,这应该可行,但添加检查约束是SUPER SLOW。我猜它是为表中的每一行重新运行我的函数,但这对于添加表级约束应该是不必要的,因为函数没有检查特定的行。有没有解决的办法?我倾向于索引视图,但想知道是否有其他选择(除了改变我的表结构)&哪种选择是最好的。

解决方案#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)

2 个答案:

答案 0 :(得分:2)

索引视图将是您建议的两个选项中更好的选择。

UDF中的这种逻辑效率低下( 评估每一行)并且很难正确。例如,参见以下帖子

答案 1 :(得分:1)

您的另一个选择是向基表添加触发器,以检查任何数据添加或修改是否符合指定的规则。