【问题标题】:One Active Record per ID每个 ID 一个 Active Record
【发布时间】:2014-03-05 13:54:47
【问题描述】:

地址表为公司和联系人共享。我有一个约束,阻止用户添加带有公司 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

我在哪里错过它?

谢谢 有限的

【问题讨论】:

    标签: sql-server-2012 constraints


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

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

      一个

      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
      

      这个解决方案似乎效果很好。

      有改进的想法吗?

      有限

      【讨论】:

        【解决方案3】:

        如果我了解您的要求,这应该可行(如果 -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;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-01-11
          • 1970-01-01
          • 1970-01-01
          • 2010-10-24
          • 2015-09-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多