1

假设我有两个表,Parent 和 Child。Parent 有一个 MaxChildren (int) 字段,Child 有一个 Enabled (bit) 字段和一个 ParentID (int) 字段链接回父记录。

我希望有一个约束,使得每个父级的 Enabled = 1 的记录不能超过 MaxChildren 记录。这意味着如果在 Child 表中插入或更新任何记录的任何尝试超过适用的 MaxChildren 值,或任何将 MaxChildren 降低到当前适用子记录数以下的尝试都将失败。

我正在使用 MS SQL Server,但我希望有一种标准的 SQL 方式。

4

1 回答 1

4

这是标准 SQL-92 入门级语法,即使用“vanilla”语法,例如CHECK在 SQL 产品中广泛实现的外键和行级约束(尽管特别是不是 mySQL):

CREATE TABLE Parent
(
 ParentID INTEGER NOT NULL, 
 MaxChildren INTEGER NOT NULL
    CHECK (MaxChildren > 0), 
 UNIQUE (ParentID),
 UNIQUE (ParentID, MaxChildren)
);

CREATE TABLE Child
(
 ParentID INTEGER NOT NULL, 
 MaxChildren INTEGER NOT NULL, 
 FOREIGN KEY (ParentID, MaxChildren)
    REFERENCES Parent (ParentID, MaxChildren)
    ON DELETE CASCADE
    ON UPDATE CASCADE, 
 OccurrenceNumber INTEGER NOT NULL, 
 CHECK (OccurrenceNumber BETWEEN 1 AND MaxChildren), 
 UNIQUE (ParentID, OccurrenceNumber)
);

我建议您避免使用位标志列。相反,您可以有第二个表而没有限制,MaxChildren然后根据行出现在哪个表中暗示启用列。您可能需要三个表来对此建模:所有子表的超类型表以及启用的子类型表。VIEW然后,您可以UNION使用隐含的 Enabled 列创建两个子类型,例如

CREATE TABLE Parents
(
 ParentID INTEGER NOT NULL, 
 MaxChildren INTEGER NOT NULL
    CHECK (MaxChildren > 0), 
 UNIQUE (ParentID),
 UNIQUE (ParentID, MaxChildren)
);

CREATE TABLE Children
(
 ChildID INTEGER NOT NULL, 
 ParentID INTEGER NOT NULL, 
 MaxChildren INTEGER NOT NULL, 
 FOREIGN KEY (ParentID, MaxChildren)
    REFERENCES Parents (ParentID, MaxChildren)
    ON DELETE CASCADE
    ON UPDATE CASCADE, 
 UNIQUE (ChildID), 
 UNIQUE (ChildID, MaxChildren),  
);

CREATE TABLE EnabledChildren
(
 ChildID INTEGER NOT NULL, 
 MaxChildren INTEGER NOT NULL, 
 FOREIGN KEY (ChildID, MaxChildren)
    REFERENCES Children (ChildID, MaxChildren)
    ON DELETE CASCADE
    ON UPDATE CASCADE, 
 OccurrenceNumber INTEGER NOT NULL, 
 CHECK (OccurrenceNumber BETWEEN 1 AND MaxChildren), 
 UNIQUE (ChildID)
);

CREATE VIEW AllChildren
AS
SELECT ChildID, 1 AS ENABLED
  FROM EnabledChildren
UNION
SELECT ChildID, 0 AS ENABLED
  FROM Children
EXCEPT
SELECT ChildID, 0 AS ENABLED
  FROM EnabledChildren;
于 2011-11-25T11:45:25.810 回答