检查约束只有三列之一为非空


61

我有一个(SQL Server)表,其中包含3种类型的结果:FLOAT,NVARCHAR(30)或DATETIME(3个单独的列)。我想确保对于任何给定的行,只有一列具有结果,其他列为NULL。实现此目的最简单的检查约束是什么?

为此,本文试图将捕获非数字结果的功能改造为现有系统。在表上添加两个新列并添加约束以防止每行出现多个结果是最经济的方法,不一定是正确的方法。

更新:抱歉,数据类型为snafu。可悲的是,我不打算将指示的结果类型解释为SQL Server数据类型,而只是一般术语,现在已修复。

Answers:


72

以下应该可以解决问题:

CREATE TABLE MyTable (col1 FLOAT NULL, col2 NVARCHAR(30) NULL, col3 DATETIME NULL);
GO

ALTER TABLE MyTable
ADD CONSTRAINT CheckOnlyOneColumnIsNull
CHECK 
(
    ( CASE WHEN col1 IS NULL THEN 0 ELSE 1 END
    + CASE WHEN col2 IS NULL THEN 0 ELSE 1 END
    + CASE WHEN col3 IS NULL THEN 0 ELSE 1 END
    ) = 1
)
GO

24

您可能需要在约束内进行三项测试,对于要为空的每一对都要进行一项测试,而对于不应该为null的列进行一项测试:

ALTER TABLE table
ADD CONSTRAINT CK_one_is_null
CHECK (
     (col1 IS NOT NULL AND col2 IS NULL AND col3 IS NULL)
  OR (col2 IS NOT NULL AND col1 IS NULL AND col3 IS NULL) 
  OR (col3 IS NOT NULL AND col1 IS NULL AND col2 IS NULL)
);

这不是那么可伸缩,我有一个带有9个外键的表,并且只有一个不应该为null,我更喜欢@MarkStoreySmith的解决方案
Amir Pashazadeh

5

这是使用内置数组函数的PostgreSQL解决方案:

ALTER TABLE your_table
ADD chk_only_one_is_not_null CHECK (array_length(array_remove(ARRAY[col1::text, col2::text, col3::text], NULL), 1) = 1);

这将比以前分别由Mark Storey和mrdenny发布的CASE或AND / OR解决方案在postgreSQL中实现更快吗?
克里斯·布里特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.