2012-09-02 91 views
3

我有3個表:的父親外鍵是男性,母親是女性,你不能是你自己的母親/父親

CREATE TABLE "Names" (
"Name" TEXT(20) NOT NULL, 
"Gender" TEXT(20) NOT NULL, 
PRIMARY KEY ("Name", "Gender") 
); 

CREATE TABLE "Snames" (
"Sname" TEXT(20) NOT NULL, 
PRIMARY KEY ("Sname") 
); 

CREATE TABLE "People" (
"ID" INTEGER NOT NULL, 
"Name" TEXT(20) NOT NULL, 
"Sname" TEXT(20) NOT NULL, 
"Gender" TEXT(1) NOT NULL, 
"FatherID" INTEGER, 
"MotherID" INTEGER, 
PRIMARY KEY ("ID") , 
CONSTRAINT "Father" FOREIGN KEY ("FatherID") REFERENCES "People" ("ID"), 
CONSTRAINT "Mother" FOREIGN KEY ("MotherID") REFERENCES "People" ("ID"), 
CONSTRAINT "Sname" FOREIGN KEY ("Sname") REFERENCES "Snames" ("Sname"), 
CONSTRAINT "Name" FOREIGN KEY ("Name", "Gender") REFERENCES "Names" ("Name", "Gender") 
); 

我的問題是與「FatherID」外鍵約束和「MotherID」,它們引用了他們自己的表格。有沒有可能只允許外鍵「性別」列中的「FatherID」和「F」中的「MotherID」?是否有可能禁止母親/父親引用同一行?

基本上:父親必須是男性。母親必須是女性。你不能成爲你自己的母親/父親。

+3

爲什麼這三個表分離的情侶,否則冗餘列的? – 2012-09-02 16:35:49

+7

如果一個人有兩個相同性別的父母,該怎麼辦;) –

+0

姓名是一個包含大約5000個帶性別姓氏的表。 Snames是大約5000個姓氏的表格。人們是一小羣人,但他們的名字引用了另外兩張桌子。但我並不認爲這很重要。 – Ashley

回答

3

我相信SQLite不支持包含與其他行動態獲得的,與外鍵的顯着的例外值表達式的約束。

您必須創建觸發器檢查父親和母親的性別。

使用此表定義:

CREATE TABLE "People" (
    "ID" INTEGER NOT NULL, 
    "Name" TEXT(20) NOT NULL, 
    "Sname" TEXT(20) NOT NULL, 
    "Gender" TEXT(1) NOT NULL, 
    "FatherID" INTEGER, 
    "MotherID" INTEGER, 
    PRIMARY KEY ("ID") , 
    CONSTRAINT "Father" FOREIGN KEY ("FatherID") REFERENCES "People" ("ID"), 
    CONSTRAINT "Mother" FOREIGN KEY ("MotherID") REFERENCES "People" ("ID"), 
    CHECK (Gender IN ('M', 'F')), 
    CHECK ("ID" NOT IN ("FatherID", "MotherID"))); 

這可能是INSERT觸發器(我會讓你寫的更新之一):

CREATE TRIGGER checkParentIdsOnInsert BEFORE INSERT ON People 
    WHEN new.FatherID IS NOT NULL OR new.MotherID IS NOT NULL 
BEGIN 
    SELECT CASE  
    WHEN ((SELECT Gender FROM People AS t1 WHERE t1.ID=new.FatherID) = 'F' 
      AND (SELECT Gender FROM People AS t2 WHERE t2.ID=new.MotherID) = 'M') 
     THEN RAISE(ABORT, 'Father must be male and mother female') 
    WHEN ((SELECT Gender FROM People AS t3 WHERE t3.ID=new.FatherID) = 'F') 
     THEN RAISE(ABORT, 'Father must be male') 
    WHEN ((SELECT Gender FROM People AS t4 WHERE t4.ID=new.MotherID) = 'M') 
     THEN RAISE(ABORT, 'Mother must be female') 
    END; 
END; 

一些簡單的測試:

sqlite> pragma foreign_keys=on; 
sqlite> INSERT INTO People (Name, SName, Gender, FatherID, MotherID) VALUES 
    ...>  ("Jo", "Blo", "M", NULL, NULL); 
sqlite> INSERT INTO People (Name, SName, Gender, FatherID, MotherID) VALUES 
    ...>  ("Za", "Bla", "F", NULL, NULL); 
sqlite> INSERT INTO People (Name, SName, Gender, FatherID, MotherID) VALUES 
    ...>  ("Bad", "Kid", "M", 2, 1); 
Error: Father must be male and mother female 
sqlite> INSERT INTO People (Name, SName, Gender, FatherID, MotherID) VALUES 
    ...>  ("Bad", "Kid", "M", 2, NULL); 
Error: Father must be male 
sqlite> INSERT INTO People (Name, SName, Gender, FatherID, MotherID) VALUES 
    ...>  ("Bad", "Kid", "M", NULL, 1); 
Error: Mother must be female 
sqlite> INSERT INTO People (Name, SName, Gender, FatherID, MotherID) VALUES 
    ...>  ("Good", "Kid", "M", 1, 2); 
sqlite> .headers on 
sqlite> .mode column 
sqlite> SELECT * FROM People; 
ID   Name  Sname  Gender  FatherID MotherID 
---------- ---------- ---------- ---------- ---------- ---------- 
1   Jo   Blo   M         
2   Za   Bla   F         
3   Good  Kid   M   1   2   
1

要應用約束的這種類型, 您需要使用觸發器哪些可以做的工作

編輯:SQLite支持觸發器。由於@catcall

+0

[SQLite支持觸發器](http://www.sqlite.org/lang_createtrigger.html)。 –

2

以下應該工作,雖然需要爲外鍵(SQL Fiddle

CREATE TABLE "People" (
"ID" INTEGER NOT NULL, 
"Name" TEXT(20) NOT NULL, 
"Sname" TEXT(20) NOT NULL, 
"Gender" TEXT(1) NOT NULL, 
"FatherID" INTEGER NULL, 
"FatherGender" TEXT(1) NULL, 
"MotherID" INTEGER NULL, 
"MotherGender" TEXT(1) NULL, 
PRIMARY KEY ("ID") , 
UNIQUE ("ID", "Gender"), 
CHECK ("ID" NOT IN ("FatherID", "MotherID")), 
CHECK ("FatherGender" = 'M'), 
CHECK ("MotherGender" = 'F'), 
CONSTRAINT "Father" FOREIGN KEY ("FatherID","FatherGender") REFERENCES "People" ("ID", "Gender"), 
CONSTRAINT "Mother" FOREIGN KEY ("MotherID","MotherGender") REFERENCES "People" ("ID", "Gender") 
); 

INSERT INTO "People" 
VALUES(1, 'Adam', '?', 'M', NULL, NULL, NULL, NULL); 

INSERT INTO "People" 
VALUES(2, 'Eve', '?', 'F', NULL, NULL, NULL, NULL); 

INSERT INTO "People" 
VALUES(3, 'Cain', '?', 'M', 1, 'M', 2, 'F'); 
+0

好戲。這個問題不是100%的匹配,但在其他地方很有用。 –