3

我需要在 T-SQL 中有一个表,它将具有以下结构

KEY     Various_Columns       Flag
 1          row 1              F
 2          row_2              F
 3          row_3              T
 4          row_4              F

没有行,或者最多一行可以有值为 T 的 Flag 列。我的开发人员声称这可以通过放置在 table 上的检查约束来实现。

问题:

  1. 是否可以在数据库级别将此类约束放置在数据库本身(即行间约束)上,而不是在用于更新或插入行的业务规则中
  2. 这样的表格是正常形式的吗?
  3. 或者正常形式需要删除标志列,而是(比如说)有另一个简单的表或变量,其中包含标志=T的行的值,即在上述情况下行=3。
4

2 回答 2

7

1 否。检查约束是每行。也没有其他约束会这样做。

您需要以下之一:

  • 触发器(所有版本)
  • 带有过滤器标志 = T 和标志上的唯一索引的索引视图 (SQL Server 2000+)
  • 过滤索引 (SQL Server 2008)

2 足够好

3 真的矫枉过正。您正在拆分相同的数据以避免上述解决方案之一。但是使用单行表,ID 列使用 FK,并且对 Flag 使用唯一约束

于 2010-10-06T19:42:35.977 回答
0

我的开发人员声称这可以通过放置在表上的检查约束来实现。

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语句,而您的单表设计需要两个;)

于 2010-10-07T09:11:33.520 回答