跨两列创建独占OR约束

时间:2013-10-28 12:59:42

标签: sql-server tsql sql-server-2012

我有一个包含两列的表格(其中包括):

NotApplicable  bit
TargetLevel    numeric(5,2)

我需要创建一个约束,以下规则适用:

  1. NotApplicable和TargetLevel不能都是NULL
  2. NotApplicable和TargetLevel不能同时具有值​​
  3. NotApplicable或TargetLevel必须具有值
  4. 我猜这是一个独家OR场景?我有一段时间了,但我现在意识到这并不能解释上面的最后一个场景:

    ALTER TABLE [dbo].[my_Table] ADD CONSTRAINT [DF_tbl_my_Table_notApplicable] DEFAULT ((0)) FOR [notApplicable]
    GO
    ALTER TABLE [dbo].[my_Table] WITH CHECK ADD CONSTRAINT [CK_tbl_my_Table] CHECK  ((COALESCE([targetLevel],[notapplicable]) IS NOT NULL))
    GO
    ALTER TABLE [dbo].[my_Table] CHECK CONSTRAINT [CK_tbl_my_Table]
    GO
    

    任何帮助完善这一点将不胜感激。另外,上面例子中实际需要的最后一个ALTER语句是吗?

2 个答案:

答案 0 :(得分:7)

这有点冗长,但我这样做的标准方法就是:

ALTER TABLE T ADD CONSTRAINT CK_One_Or_Tother CHECK (
    (NotApplicable IS NULL and TargetLevel IS NOT NULL) OR
    (NotApplicable IS NOT NULL and TargetLevel IS NULL)
)

  

另外,上面的例子中实际需要的最后一个ALTER语句是吗?

ALTER TABLE [dbo].[my_Table] CHECK CONSTRAINT [CK_tbl_my_Table]

只有在您创建或更改约束并指定NOCHECK或以其他方式禁用先前的约束并现在启用它时,才需要这样做。创建约束的默认设置是启用它们。


对于大量必须填写的列,我倾向于切换到另一种结构:

ALTER TABLE T ADD CONSTRAINT CK_One_Or_Tother CHECK (
    1 = (
        CASE WHEN ColumnA IS NOT NULL THEN 1 ELSE 0 END +
        CASE WHEN ColumnB IS NOT NULL THEN 1 ELSE 0 END +
        CASE WHEN ColumnC IS NOT NULL THEN 1 ELSE 0 END +
        CASE WHEN ColumnD IS NOT NULL THEN 1 ELSE 0 END
    )
)

这样做的好处是只能为每一列命名一次,但看起来有点难看。

答案 1 :(得分:0)

两列方案的替代语法是:

ALTER TABLE T ADD CONSTRAINT CK_One_Or_Tother CHECK (
     (NotApplicable IS NULL     OR TargetLevel IS NULL)
 AND (NotApplicable IS NOT NULL OR TargetLevel IS NOT NULL)
)