sql - 父亲是男性,母亲是女性的外键,你不能是你自己的母亲/父亲

标签 sql database sqlite foreign-keys constraints

我有 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”的外键约束,它们引用了它们自己的表。是否可以只允许外键,其中“M”在“FatherID”的性别列中,“F”用于“MotherID”?是否可以禁止母亲/父亲引用同一行?

基本上:父亲必须是男性。母亲必须是女性。你不能做自己的母亲/父亲。

最佳答案

我相信 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 触发器(我会让你写一个 UPDATE 触发器):

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         

关于sql - 父亲是男性,母亲是女性的外键,你不能是你自己的母亲/父亲,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12237660/

相关文章:

c# - 系统.Data.OleDb.OleDbException : Data type mismatch in criteria expression

sql - Oracle 包间歇性返回空表的问题

mysql - 安排 mysql 表每 24 小时清空一次

database - 当复数和单数形式为奇数或相同时的表和列命名约定

c# - 通过网络连接到 SQLite 数据库

android - 是否有可能使用 wi-fi 在两个 android 手机之间同步 sqlite 表数据

javascript - 如何使用 Nodejs 将 SQLite 索引放入变量中?

mysql - 选择多部分(多仓库)订单时出现问题

sql - BigQuery JOIN 错误

php - 从 PHP 表单发布到 mySQL 中的多行