2011-11-25 95 views
1

假設我有兩張表,父母和孩子。 Parent有一個MaxChildren(int)字段,Child有一個Enabled(位)字段和一個ParentID(int)字段,鏈接回父記錄。如何約束SQL表中允許的記錄數?

我想有一個約束,以便不能超過MaxChildren記錄爲Enabled = 1的每個父級。這將意味着任何嘗試插入或更新Child表中的任何記錄將失敗if它會超過適用的MaxChildren值,或者嘗試將MaxChildren降低到當前適用的Child記錄數以下時將失敗。

我正在使用MS SQL Server,但我希望有一個標準的SQL方式。

+0

如何使用某些觸發器? –

回答

4

這是標準的SQL-92入門級語法,即使用「香草」的語法如外鍵和行級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限制的情況下擁有第二個表,然後根據行所在的表顯示Enabled列。您可能需要三個表來對此進行建模:所有子類型爲Enabled的子類型的子表的超類型表。然後,您可以創建一個VIEWUNION這兩個子類型,並在默認的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; 
+0

我喜歡'OccurrenceNumber'想法,因此而不是Enabled,Occurence將是NULL或NOT NULL。在將Occurrence更新爲非空值(啓用)之前,代碼必須首先選擇未使用的Occurence值。謝謝。 – billpg

+0

我喜歡這樣,但是如何在必要時更改'MaxChildren'的值? –

+0

後續問題:http://stackoverflow.com/questions/8270377/how-to-update-an-sql-table-with-a-unique-number-within-a-range – billpg