每个ID一个活动记录

时间:2014-03-04 16:57:48

标签: sql-server-2012 constraints

地址表是为公司和联系人共享的。我有一个约束,阻止用户添加包含公司ID和联系人ID的记录。我正在尝试添加另一个约束,使每个公司ID或联系人ID只有1个活动(ACTIVE FLAG ='TRUE')地址。但我希望能够无限制地无效(ACTIVE FLAG ='FALSE')。

ALTER TABLE [dbo].[ADDRESSES]  WITH CHECK ADD  CONSTRAINT [chk_ONLY_ONE_ACTIVE_ADDRESS] CHECK  (([COMPANY_ID] IS NOT NULL AND [CONTACT_ID] IS NULL AND [ACTIVE] = 'TRUE' OR [COMPANY_ID] IS NULL AND [CONTACT_ID] IS NOT NULL AND [ACTIVE] = 'TRUE' OR [COMPANY_ID] IS NULL AND [CONTACT_ID] IS NOT NULL AND [ACTIVE] = 'FALSE' OR [COMPANY_ID] IS NOT NULL AND [CONTACT_ID] IS NULL AND [ACTIVE] = 'FALSE'))
GO

我错过了哪里?

由于 jlimited

3 个答案:

答案 0 :(得分:0)

您正在为联系人ID和公司ID的两种组合添加约束“active = true”和“active = false”,因此它是一个重言式,您也可以删除此约束。 我认为强制执行规则的唯一方法是“只有一个活动标志,0到多个非活动标志”是触发器。

答案 1 :(得分:0)

感谢Jayvee的回复。这是我想出的解决方案。

我首先创建了两个函数......

CREATE FUNCTION [dbo].[fnCheckForActiveContactAddress](
    @id int
)
RETURNS INT
AS
BEGIN
    DECLARE @result INT

    IF @id IS NOT NULL
        SET @result = ISNULL((select count(*) from dbo.Addresses where CONTACT_ID = @ID AND ACTIVE = 'TRUE'),0)
    ELSE
        SET @result = 1

RETURN @result
END
GO

两个

CREATE FUNCTION [dbo].[fnCheckForActiveCompanyAddress](
    @id int
)
RETURNS INT
AS
BEGIN
    DECLARE @result INT

    If @id IS NOT NULL
        SET @result = ISNULL((select count(*) from dbo.Addresses where COMPANY_ID = @ID AND ACTIVE = 'TRUE'),0)
    ELSE
        SET @result = 1

RETURN @result
END
GO

然后我添加了以下约束......

ALTER TABLE [dbo].[ADDRESSES]  WITH CHECK ADD  CONSTRAINT [chk_COMPANY_OR_CONTACT] CHECK  (([COMPANY_ID] IS NOT NULL AND [CONTACT_ID] IS NULL OR [COMPANY_ID] IS NULL AND [CONTACT_ID] IS NOT NULL))
GO

ALTER TABLE [dbo].[ADDRESSES]  WITH NOCHECK ADD  CONSTRAINT [CHK_ADDRESSES_ONLY_ONE_ACTIVE_CONTACT] CHECK  (([dbo].[fnCheckForActiveContactAddress]([CONTACT_ID])=(1)))
GO

ALTER TABLE [dbo].[ADDRESSES]  WITH NOCHECK ADD  CONSTRAINT [CHK_ADDRESSES_ONLY_ONE_ACTIVE_COMPANY] CHECK  (([dbo].[fnCheckForActiveCompanyAddress]([COMPANY_ID])=(1)))
GO

此解决方案似乎运作良好。

有关改善它的想法吗?

jlimited

答案 2 :(得分:0)

如果我理解您的要求,这应该有效(如果-1不是有效的CompanyID或ContactID):

create table T (
  CompanyID int,
  ContactID int,
  BothIDs as
    CASE WHEN CompanyID IS NOT NULL and ContactID IS NOT NULL
    THEN 1 ELSE 0 END PERSISTED
  check (BothIDs = 0),
  ActiveFlag varchar(5) check (ActiveFlag in ('TRUE','FALSE')),
  ActiveCheck as
    CASE WHEN ActiveFlag='TRUE' then -1 ELSE COALESCE(CompanyID,ContactID) END,
  unique (ActiveCheck)
);

insert into T values
  (1,NULL,'FALSE'),
  (NULL,2,'FALSE'),
  (3,NULL,'TRUE'),
  (4,NULL,'FALSE');
GO

UPDATE T SET
  ActiveFlag = 'TRUE'
WHERE CompanyID = 4;