如何使用条件在多个列上添加唯一约束?

时间:2012-02-23 11:54:53

标签: sql sql-server sql-server-2008 sql-server-2005 tsql

问题:

我想在映射表(n:n)上添加唯一约束 我希望可以插入新值,但前提是TEST_FK_UID,TEST_DateFrom和TEST_DateTo不等于已存在的条目。

问题是状态字段 状态1表示有效..
状态!= 1表示不活动/已删除..


因此,当然可以插入具有相同FK,DateFrom和DateTo,IF的新条目 - 并且仅当 - 现有条目的状态(所有现有条目,因为您可以插入,删除,插入,删除,插入,删除,等)是!= 1

这是我到目前为止所做的:

CREATE TABLE dbo._________Test  
(
     TEST_UID uniqueidentifier NOT NULL 
    ,TEST_FK_UID uniqueidentifier NOT NULL 
    ,TEST_DateFrom DateTime NOT NULL 
    ,TEST_DateTo DateTime NOT NULL  
    ,TEST_Status int NOT NULL 
    ,UNIQUE(TEST_FK_UID, TEST_DateFrom, TEST_DateTo, TEST_Status) 
); 

3 个答案:

答案 0 :(得分:3)

你做不到。但是,您可以创建唯一的索引。它的功能类似,我期待你足够好。

CREATE UNIQUE INDEX MyIndex
ON _________Test
( TEST_FK_UID
, TEST_DateFrom
, TEST_DateTo )
WHERE TEST_Status = 1

唯一索引和唯一约束之间最重要的区别是,您无法在另一个引用唯一索引的表中创建外键。 编辑:as Martin指出,事实并非如此,外键可以引用未经过滤的唯一索引。

答案 1 :(得分:0)

在INSERT,UPDATE操作上使用而不是触发器.. 并使用INSERTED表中的值检查现有值(在触发器的情况下创建) 如果INSERTED表中的状态为1,如果它是唯一的,则执行插入操作或仅使用某些消息中止..

答案 2 :(得分:0)

这很可能,就像这样 (基本功劳归于:https://stackoverflow.com/users/103075):

<小时/> 修改:
好的,迂腐地看到它不是一个独特的约束,它是一个检查约束,但是WTF - 它具有相同的效果并且也适用于SQL-Server 2005,并且(条件)条件可以按客户配置(替换SET @bNoCheckForThisCustomer =' false'选择配置表) - 使用唯一索引AFAIK无法实现...;)


请注意以下这一行:

AND ZO_RMMIO_UID != @in_ZO_RMMIO_UID

(ZO_RMMIO_UID是n:n映射表的唯一主键)
这很重要,因为检查约束似乎与onAfterInsert触发器类似。
如果缺少这一行,它也会自行检查,这导致函数总是返回true ...


IF  EXISTS (SELECT * FROM sys.check_constraints WHERE object_id = OBJECT_ID(N'[dbo].[CheckNoDuplicate_T_ZO_AP_Raum_AP_Ref_Mietobjekt]') AND parent_object_id = OBJECT_ID(N'[dbo].[T_ZO_AP_Raum_AP_Ref_Mietobjekt]'))
ALTER TABLE [dbo].[T_ZO_AP_Raum_AP_Ref_Mietobjekt] DROP CONSTRAINT [CheckNoDuplicate_T_ZO_AP_Raum_AP_Ref_Mietobjekt]
GO





IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fu_InsertCheck_IsDuplicate_T_ZO_AP_Raum_AP_Ref_Mietobjekt]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[fu_InsertCheck_IsDuplicate_T_ZO_AP_Raum_AP_Ref_Mietobjekt]
GO





-- ========================================================================
-- Author:            Me
-- Create date:       09.08.2010
-- Last modified:     09.08.2010
-- Description:   Conditionally check if row is a duplicate
-- ========================================================================

-- PRE:  UID, Valid RM_UID, Valid MIO_UID, 
--       Valid datetime-from for db usr language, valid datetime-to for db usr language
-- POST: True/False


CREATE  FUNCTION [dbo].[fu_InsertCheck_IsDuplicate_T_ZO_AP_Raum_AP_Ref_Mietobjekt](@in_ZO_RMMIO_UID uniqueidentifier, @in_ZO_RMMIO_RM_UID AS uniqueidentifier, @in_ZO_RMMIO_MIO_UID as uniqueidentifier, @in_ZO_RMMIO_DatumVon AS datetime, @in_ZO_RMMIO_DatumBis AS datetime)
    RETURNS bit
AS
    BEGIN   

        DECLARE @bIsDuplicate AS bit
        SET @bIsDuplicate = 'false'     


        DECLARE @bNoCheckForThisCustomer AS bit
        SET @bNoCheckForThisCustomer = 'false'

        IF @bNoCheckForThisCustomer = 'true'
            RETURN @bIsDuplicate 




        IF EXISTS
        (
            SELECT 
                 ZO_RMMIO_UID
                ,ZO_RMMIO_RM_UID
                ,ZO_RMMIO_MIO_UID
            FROM T_ZO_AP_Raum_AP_Ref_Mietobjekt 
            WHERE ZO_RMMIO_Status = 1 
            AND ZO_RMMIO_UID != @in_ZO_RMMIO_UID
            AND ZO_RMMIO_RM_UID = @in_ZO_RMMIO_RM_UID 
            AND ZO_RMMIO_MIO_UID = @in_ZO_RMMIO_MIO_UID 
            AND ZO_RMMIO_DatumVon = @in_ZO_RMMIO_DatumVon 
            AND ZO_RMMIO_DatumBis = @in_ZO_RMMIO_DatumBis 
        )
            SET @bIsDuplicate = 'true'

        RETURN @bIsDuplicate
    END


GO




ALTER TABLE [dbo].[T_ZO_AP_Raum_AP_Ref_Mietobjekt]  WITH NOCHECK ADD  CONSTRAINT [CheckNoDuplicate_T_ZO_AP_Raum_AP_Ref_Mietobjekt] 
CHECK  
(
    NOT 
    (
        dbo.fu_InsertCheck_IsDuplicate_T_ZO_AP_Raum_AP_Ref_Mietobjekt(ZO_RMMIO_UID, ZO_RMMIO_RM_UID, ZO_RMMIO_MIO_UID, ZO_RMMIO_DatumVon, ZO_RMMIO_DatumBis) = 1 
    )
)
GO


ALTER TABLE [dbo].[T_ZO_AP_Raum_AP_Ref_Mietobjekt] CHECK CONSTRAINT [CheckNoDuplicate_T_ZO_AP_Raum_AP_Ref_Mietobjekt]
GO

这是一个测试用例:

CREATE TABLE [dbo].[T_ZO_AP_Raum_AP_Ref_Mietobjekt](
    [ZO_RMMIO_UID] [uniqueidentifier] NOT NULL,  -- <== PRIMARY KEY
    [ZO_RMMIO_RM_UID] [uniqueidentifier] NOT NULL,
    [ZO_RMMIO_MIO_UID] [uniqueidentifier] NOT NULL,
    [ZO_RMMIO_DatumVon] [datetime] NOT NULL,
    [ZO_RMMIO_DatumBis] [datetime] NOT NULL,
    [ZO_RMMIO_Status] [int] NOT NULL,
    [ZO_RMMIO_Bemerkung] [text] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO



/*
DELETE FROM T_ZO_AP_Raum_AP_Ref_Mietobjekt 
WHERE ZO_RMMIO_Status = 1 
AND ZO_RMMIO_RM_UID = '2007B6F5-9010-4979-AB39-00057DA353C0' 
AND ZO_RMMIO_MIO_UID = 'FFA177E9-971E-4500-805D-00116F708E7B'
*/


INSERT INTO T_ZO_AP_Raum_AP_Ref_Mietobjekt
(
     ZO_RMMIO_UID
    ,ZO_RMMIO_RM_UID
    ,ZO_RMMIO_MIO_UID
    ,ZO_RMMIO_DatumVon
    ,ZO_RMMIO_DatumBis
    ,ZO_RMMIO_Status
    ,ZO_RMMIO_Bemerkung
)
VALUES
(
     NEWID() --<ZO_RMMIO_UID, uniqueidentifier,>
    ,'2007B6F5-9010-4979-AB39-00057DA353C0' --<ZO_RMMIO_RM_UID, uniqueidentifier,>
    ,'FFA177E9-971E-4500-805D-00116F708E7B' --<ZO_RMMIO_MIO_UID, uniqueidentifier,>
    ,'01.01.2012' --<ZO_RMMIO_DatumVon, datetime,>
    ,'31.12.2999' --<ZO_RMMIO_DatumBis, datetime,>
    ,1 --<ZO_RMMIO_Status, int,>
    ,NULL--<ZO_RMMIO_Bemerkung, text,>
)
GO



INSERT INTO T_ZO_AP_Raum_AP_Ref_Mietobjekt
(
     ZO_RMMIO_UID
    ,ZO_RMMIO_RM_UID
    ,ZO_RMMIO_MIO_UID
    ,ZO_RMMIO_DatumVon
    ,ZO_RMMIO_DatumBis
    ,ZO_RMMIO_Status
    ,ZO_RMMIO_Bemerkung
)
VALUES
(
     NEWID() --<ZO_RMMIO_UID, uniqueidentifier,>
    ,'2007B6F5-9010-4979-AB39-00057DA353C0' --<ZO_RMMIO_RM_UID, uniqueidentifier,>
    ,'FFA177E9-971E-4500-805D-00116F708E7B' --<ZO_RMMIO_MIO_UID, uniqueidentifier,>
    ,'01.01.2012' --<ZO_RMMIO_DatumVon, datetime,>
    ,'31.12.2999' --<ZO_RMMIO_DatumBis, datetime,>
    ,1 --<ZO_RMMIO_Status, int,>
    ,NULL--<ZO_RMMIO_Bemerkung, text,>
)
GO

SELECT [ZO_RMMIO_UID]
      ,[ZO_RMMIO_RM_UID]
      ,[ZO_RMMIO_MIO_UID]
      ,[ZO_RMMIO_DatumVon]
      ,[ZO_RMMIO_DatumBis]
      ,[ZO_RMMIO_Status]
      ,[ZO_RMMIO_Bemerkung]
  FROM [T_ZO_AP_Raum_AP_Ref_Mietobjekt]