如何界定外键的可能值?

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       |
+------------+-------------+--------------+

所以现在有一个问题,我无法解决。当我INSERTUPDATE一行时,我设置了groups_id,但这也可以是一个不属于组织的groups_id。 发生这种情况是因为 GROUPS 中的所有 ID 都是有效的 FK 值。这是我想避免的事情。应该只能 insertupdate 具有 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。可以使用触发器实现其他语义。“