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

Dav*_*rke 75 sql-server constraint

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

这样做的背景是试图改进将非数字结果捕获到现有系统中的能力。使用约束向表中添加两个新列以防止每行超过一个结果是最经济的方法,但不一定是正确的方法。

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

Mar*_*ith 90

以下应该可以解决问题:

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
Run Code Online (Sandbox Code Playgroud)

  • 通过使用“IN”,这可以进一步推广为“全部为空或不为空”。示例:`CHECK (IIF(ConsentDate 为 null, 1, 0) + IIF(ConsentingUserID 为 null, 1, 0) + IIF(ConsentingClientIdentifiers 为 null, 1, 0) in (0, 3))` (3认同)

mrd*_*nny 25

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

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)
);
Run Code Online (Sandbox Code Playgroud)


小智 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);
Run Code Online (Sandbox Code Playgroud)

  • 与前面提到的分别由 Mark Storey 和 mrdenny 发布的 CASE 或 AND/OR 解决方案相比,这在 postgreSQL 中的实现会更快吗? (2认同)