MySQL:两个n:1关系,但不是两个关系

Dan*_*gen 5 mysql database-design relational-database polymorphic-associations

对不起标题,很难解释.

我需要一个与此类似的数据模型: 替代文字

如您所见,一组可以属于用户或学校.我的问题:它应该只允许属于用户或学校.但绝不是两个在同一时间.

我怎么解决这个问题?

Bil*_*win 6

您当前的设计称为独占弧,其中sets表有两个外键,并且只需要其中一个非空.这是实现多态关联的一种方法,因为给定的外键只能引用一个目标表.

另一种解决方案是让一个共同的"超表",无论usersschools引用,然后使用该作为的母公司sets.

create table set_owner

create table users 
  PK is also FK --> set_owner

create table schools
  PK is also FK --> set_owner

create table sets 
  FK --> set_owner
Run Code Online (Sandbox Code Playgroud)

您可以将其视为与OO建模中的接口类似:

interface SetOwner { ... }

class User implements SetOwner { ... }

class School implements SetOwner { ... }

class Set {
  SetOwner owner;
}
Run Code Online (Sandbox Code Playgroud)

你的意见:

所以SetOwner表包含UserID和SchoolID,对吗?这意味着我不会被允许为用户和学校使用相同的ID.我该如何强制执行此操作?

让SetOwners表生成id值.您必须先插入SetOwners,然后才能插入用户或学校.因此,使用户和学校中的ID 不会自动递增; 只需使用SetOwners生成的值:

INSERT INTO SetOwners DEFAULT VALUES; -- generates an id
INSERT INTO Schools (id, name, location) VALUES (LAST_INSERT_ID(), 'name', 'location');
Run Code Online (Sandbox Code Playgroud)

这样,学校和用户都不会使用给定的id值.

如果我想获取集合的所有者类型,我是否需要在SetOwner表中使用ownerType属性?

你当然可以这样做.实际上,可能有其他列对于用户和学校都是通用的,您可以将这些列放在超级SetOwners中.这进入了Martin Fowler的类表继承模式.

如果我想得到学校或用户的名字(无论哪种类型),我可以用一个查询来完成,或者我需要两个查询(首先获取类型,第二个获取名称)?

你需要做一个加入.如果您从给定的Set中查询并且您知道它属于用户(而不是学校),则可以跳过加入SetOwners并直接加入用户.联接不一定要通过外键.

SELECT u.name FROM Sets s JOIN Users u ON s.SetOwner_id = u.id WHERE ...
Run Code Online (Sandbox Code Playgroud)

如果您不知道给定集是属于用户还是学校,则必须对两者进行外部联接:

SELECT COALESCE(u.name, sc.name) AS name 
FROM Sets s 
LEFT OUTER JOIN Users u ON s.SetOwner_id = u.id
LEFT OUTER JOIN Schools sc ON s.SetOwner_id = sc.id 
WHERE ...
Run Code Online (Sandbox Code Playgroud)

您知道SetOwner_id必须匹配一个或另一个表,Users或Schools,但不能同时匹配两者.