2

我有一个有两列的表(除其他外):

NotApplicable  bit
TargetLevel    numeric(5,2)

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

  1. NotApplicable 和 TargetLevel 不能同时为 NULL
  2. NotApplicable 和 TargetLevel 不能同时具有值
  3. NotApplicable 或 TargetLevel 必须有一个值

我想这是一个排他性的 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 语句?

4

2 回答 2

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
    )
)

其优点是每列只命名一次,但看起来有点难看。

于 2013-10-28T13:13:23.807 回答
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)
)
于 2015-03-10T14:28:28.130 回答