如何界定外键的可能值?
How can I delimit the possible values of a foreign key?
我在 MySQL 数据库中有三个 table。
这是与组织相关的主要内容 table。每个组织都有一个唯一的标识符,它也是某些 table 中的外键。
org
+------------+-------------+
| org_id | name |
+------------+-------------+
| 1 | a |
| 2 | b |
| 3 | c |
+------------+-------------+
这是群组 table。组织可以有很多组。
groups
FOREIGN KEY (ORG_ID) REFERENCES ORG (ID);
+------------+-------------+----------+
| ID | org_id | name |
+------------+-------------+ ---------+
| 1 | 1 | Group1 |
| 2 | 2 | Group2 |
| 3 | 2 | Group3 |
+------------+-------------+----------+
这是我要在其中执行更新的提要 table。
一个供稿只能有一个关联组。
feed
FOREIGN KEY (GROUP_ID) REFERENCES GROUPS (ID);
+------------+-------------+--------------+
| ID | org_id | group_id |
+------------+-------------+ -------------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 1 | NULL |
| 4 | 2 | 3 |
+------------+-------------+--------------+
所以现在有一个问题,我无法解决。当我INSERT
或UPDATE
一行时,我设置了groups_id
,但这也可以是一个不属于组织的groups_id
。
发生这种情况是因为 GROUPS 中的所有 ID 都是有效的 FK 值。这是我想避免的事情。应该只能 insert
或 update
具有 groups_id
的行也具有与 feeds.org_id
.
中相同的 org_id
如您所见,数据现在没有问题了。但是当我尝试制作这个 INSERT INTO feed VALUES (4, 2, 1)
时,很高兴看到一个错误。是的,对了,我错过了一个可爱的错误....
我很难把它们联系起来。我似乎缺少一种信息或方法。我一直在寻找很多,但我不知道用什么词来描述我的问题。
所以我问你,你能给我小费吗?
编辑:
所有提要和所有组都与一个组织相关,该组织具有一个标识符。一个组织可以创建 feeds/messages。当此提要与组无关时,此提要是 public。对于特殊提要,他们可以创建一个组。该组与该特殊组织有关。
这有效,一切都很好:
UPDATE feed
SET title = "Title", message = "Message", groups_id = "1"
WHERE id = "1" AND org_id = "1"
但这也适用:
UPDATE feed
SET title = "Title", message = "Message", groups_id = "2"
WHERE id = "1" AND org_id = "1"
问题是,可以将一个组与一个提要相关联(与组织 1 相关联),而该组不与组织相关联(组 2 与组织 2 相关联)。
所以我的想法是,有没有办法通过 FOREIGN KEY 或类似方法(检查、连接、子查询)来解决这个问题。或者我应该考虑我的数据库设计?
我认为组合外键可以解决您的问题:
create table agroup (
id int primary key,
orgid int,
UNIQUE (id,orgid)
);
create table feed (
id int primary key,
groupid int,
orgid int,
FOREIGN KEY (groupid, orgid) REFERENCES agroup(id, orgid)
);
insert into agroup values (10, 1), (20, 1), (30, 2), (40, NULL);
insert into feed values (100,10,1), (101, 20, 1);
insert into feed values (102, 40, NULL); # works
insert into feed values (103, NULL, 1); # works as well
# insert into feed values (110,10,2); # yields error "Cannot add or update a child row: a foreign key constraint fails"
注意UNIQUE(id,orgid)
,这似乎是必要的。虽然我不明白为什么 agroup(id primary key)
不足以使 agroup(id,orgid)
也变得唯一,但我在没有这个显式 unique(id,orgid
)-约束的情况下遇到了编译器错误。文档说引用的属性必须被索引。不管怎样,你的问题应该已经解决了。
编辑:扩展示例,现在还演示了引用属性中 NULL 值的情况。
至少在 MySQL 中,复合外键约束允许在引用(子)行中使用 NULL 值,无论父 table 是否包含具有相应 NULL 值的行。如果插入一行外键属性为 NULL 值,则外键约束将被简单地忽略。 Confer mysql foreign key semantics,它说:
“... MySQL 本质上实现了 MATCH SIMPLE 定义的语义,它允许外键全部或部分为 NULL。在这种情况下,包含此类外键的 (child table) 行是允许插入,并且不匹配引用(父)中的任何行 table。可以使用触发器实现其他语义。“
我在 MySQL 数据库中有三个 table。 这是与组织相关的主要内容 table。每个组织都有一个唯一的标识符,它也是某些 table 中的外键。
org
+------------+-------------+
| org_id | name |
+------------+-------------+
| 1 | a |
| 2 | b |
| 3 | c |
+------------+-------------+
这是群组 table。组织可以有很多组。
groups
FOREIGN KEY (ORG_ID) REFERENCES ORG (ID);
+------------+-------------+----------+
| ID | org_id | name |
+------------+-------------+ ---------+
| 1 | 1 | Group1 |
| 2 | 2 | Group2 |
| 3 | 2 | Group3 |
+------------+-------------+----------+
这是我要在其中执行更新的提要 table。 一个供稿只能有一个关联组。
feed
FOREIGN KEY (GROUP_ID) REFERENCES GROUPS (ID);
+------------+-------------+--------------+
| ID | org_id | group_id |
+------------+-------------+ -------------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 1 | NULL |
| 4 | 2 | 3 |
+------------+-------------+--------------+
所以现在有一个问题,我无法解决。当我INSERT
或UPDATE
一行时,我设置了groups_id
,但这也可以是一个不属于组织的groups_id
。
发生这种情况是因为 GROUPS 中的所有 ID 都是有效的 FK 值。这是我想避免的事情。应该只能 insert
或 update
具有 groups_id
的行也具有与 feeds.org_id
.
org_id
如您所见,数据现在没有问题了。但是当我尝试制作这个 INSERT INTO feed VALUES (4, 2, 1)
时,很高兴看到一个错误。是的,对了,我错过了一个可爱的错误....
我很难把它们联系起来。我似乎缺少一种信息或方法。我一直在寻找很多,但我不知道用什么词来描述我的问题。
所以我问你,你能给我小费吗?
编辑:
所有提要和所有组都与一个组织相关,该组织具有一个标识符。一个组织可以创建 feeds/messages。当此提要与组无关时,此提要是 public。对于特殊提要,他们可以创建一个组。该组与该特殊组织有关。
这有效,一切都很好:
UPDATE feed
SET title = "Title", message = "Message", groups_id = "1"
WHERE id = "1" AND org_id = "1"
但这也适用:
UPDATE feed
SET title = "Title", message = "Message", groups_id = "2"
WHERE id = "1" AND org_id = "1"
问题是,可以将一个组与一个提要相关联(与组织 1 相关联),而该组不与组织相关联(组 2 与组织 2 相关联)。
所以我的想法是,有没有办法通过 FOREIGN KEY 或类似方法(检查、连接、子查询)来解决这个问题。或者我应该考虑我的数据库设计?
我认为组合外键可以解决您的问题:
create table agroup (
id int primary key,
orgid int,
UNIQUE (id,orgid)
);
create table feed (
id int primary key,
groupid int,
orgid int,
FOREIGN KEY (groupid, orgid) REFERENCES agroup(id, orgid)
);
insert into agroup values (10, 1), (20, 1), (30, 2), (40, NULL);
insert into feed values (100,10,1), (101, 20, 1);
insert into feed values (102, 40, NULL); # works
insert into feed values (103, NULL, 1); # works as well
# insert into feed values (110,10,2); # yields error "Cannot add or update a child row: a foreign key constraint fails"
注意UNIQUE(id,orgid)
,这似乎是必要的。虽然我不明白为什么 agroup(id primary key)
不足以使 agroup(id,orgid)
也变得唯一,但我在没有这个显式 unique(id,orgid
)-约束的情况下遇到了编译器错误。文档说引用的属性必须被索引。不管怎样,你的问题应该已经解决了。
编辑:扩展示例,现在还演示了引用属性中 NULL 值的情况。
至少在 MySQL 中,复合外键约束允许在引用(子)行中使用 NULL 值,无论父 table 是否包含具有相应 NULL 值的行。如果插入一行外键属性为 NULL 值,则外键约束将被简单地忽略。 Confer mysql foreign key semantics,它说: “... MySQL 本质上实现了 MATCH SIMPLE 定义的语义,它允许外键全部或部分为 NULL。在这种情况下,包含此类外键的 (child table) 行是允许插入,并且不匹配引用(父)中的任何行 table。可以使用触发器实现其他语义。“