SQL数据库中的约束

时间:2010-10-06 19:37:30

标签: sql sql-server-2005 tsql check-constraints

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

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

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

问题:

  1. 可以在数据库级别对数据库本身(即行间约束)进行此类约束,而不是在更新或插入行的业务规则中
  2. 这样的表格是否正常?
  3. 或者普通形式需要删除Flag列,而是(比方说)有另一个简单的表或变量,其中包含具有Flag = T的行的值,即在上面的情况下row = 3.

2 个答案:

答案 0 :(得分:7)

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

您需要以下其中一项:

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

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