我的开发人员声称这可以通过放置在表上的检查约束来实现。
SQL Server 不直接**支持CHECK
约束中的子查询(Full SQL-92 的要求;SQL Server 仅与入门级 SQL-92 兼容,广义而言)。
虽然几乎可以肯定在 SQL Server 中执行此约束有更好的方法,但纯粹出于兴趣,它确实可以使用行级CHECK
约束和UNIQUE
约束来实现,例如这里有一种方法:
CREATE TABLE YourStuff
(
key_col INTEGER NOT NULL UNIQUE,
Various_Columns VARCHAR(8) NOT NULL,
Flag CHAR(1) DEFAULT 'F' NOT NULL
CHECK (Flag IN ('F', 'T')),
Flag_key INTEGER UNIQUE,
CHECK (
(Flag = 'F' AND Flag_key = key_col)
OR
(Flag = 'T' AND Flag_key = NULL)
)
);
这里的问题是您需要Flag_key
“手动”维护列的值。用计算列替换 +CHECK
列将意味着自动维护这些值:
CREATE TABLE YourStuff
(
key_col INTEGER NOT NULL UNIQUE,
Various_Columns VARCHAR(8) NOT NULL,
Flag CHAR(1) DEFAULT 'F' NOT NULL
CHECK (Flag IN ('F', 'T')),
Flag_key AS (
CASE WHEN Flag = 'F' THEN key_col
ELSE NULL END
),
UNIQUE (Flag_key)
);
** 虽然 SQL Server 不直接支持约束中的子查询,但在某些情况下使用用户定义函数 (UDF)CHECK
有一种解决方法,例如
CREATE FUNCTION dbo.CountTFlags ()
RETURNS INTEGER
AS
BEGIN
DECLARE @return INTEGER;
SET @return = (
SELECT COUNT(*)
FROM YourStuff
WHERE Flag = 'T'
);
RETURN @return;
END;
CREATE TABLE YourStuff
(
key_col INTEGER NOT NULL UNIQUE,
Various_Columns VARCHAR(8) NOT NULL,
Flag CHAR(1) DEFAULT 'F' NOT NULL
CHECK (Flag IN ('F', 'T')),
CHECK (1 >= dbo.CountTFlags())
);
请注意,UDF 方法并非在所有情况下都有效,因此需要谨慎。重要的一点是 UDF 将针对受影响的每一行进行评估(而不是在 SQL 语句或事务级别,如您所料)。在这种情况下,对于受影响的每一行,约束都必须为真,因此——我认为!——很安全。有关更多详细信息,请参阅David Portas 的 CHECK 约束问题。
就个人而言,我会简单地使用第二个表来建模Flag
,它只涉及键和外键,例如
CREATE TABLE YourStuff
(
key_col INTEGER NOT NULL UNIQUE,
Various_Columns VARCHAR(8) NOT NULL
);
CREATE TABLE YourStuffFlag
(
key_col INTEGER NOT NULL UNIQUE
REFERENCES YourStuff (key_col)
);
[我的] 表是正常形式的吗?
您应该以第五范式(5NF)为目标。您是否实现了这一点取决于Various_Columns
. 我不相信您Flag
符合 5NF 的要求,并且我没有看到任何更新、删除或插入异常(这是规范化点,但 5NF 设计仍然会出现异常)。也就是说,要切换获得属性的行flag
,我的两表设计需要一个UPDATE
语句,而您的单表设计需要两个;)