我需要在T-SQL中有一个表,它具有以下结构
KEY Various_Columns Flag
1 row 1 F
2 row_2 F
3 row_3 T
4 row_4 F
没有行,或者最多只有一行可以使用值T的Flag列。我的开发人员声称这可以通过放置在表上的检查约束来实现。
问题:
答案 0 :(得分:7)
1否。检查约束是每行。没有其他约束也会这样做。
您需要以下其中一项:
2足够好
3真的过度杀伤力。您正在拆分相同的数据以避免上述解决方案。但是使用一行表,FK用于ID列,以及对Flag
的唯一约束答案 1 :(得分:0)
我的开发人员声称可以这样做 通过检查约束实现 放在桌子上。
SQL Server不直接**支持CHECK
约束中的子查询(完整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没有直接支持CHECK
约束中的子查询,但在某些情况下使用用户定义函数(UDF)有一种解决方法例如
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方法在每种情况下都不起作用,并且需要谨慎。重要的是,将针对受影响的每一行(而不是在SQL语句或事务级别,如您所料)评估UDF。在这种情况下,受影响的每一行都需要约束,因此 - 我认为! - 这很安全。有关详细信息,请参阅Trouble with CHECK Constraints by David Portas。
就个人而言,我只是使用第二个表来建模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
语句,而单表设计需要两个;)