Mysql外键,它引用了两列,这两列是两个不同表中的主键

时间:2017-02-25 16:31:06

标签: mysql database

让我们说有三个表叫老师,学生和消息。

教师:

-----------
ID | name |
-----------
t_1| Dani |
-----------
t_2| Billy|
-----------

生:

-------------
ID | name   |
-------------
s_1| Luckas |
-------------
s_2| Oliver |
-------------

消息:

--------------------------------
| ID | sender_ID | receiver_ID |
--------------------------------
| 1  | s_1       | s_2         |
--------------------------------
| 2  | s_1       | t_1         |
--------------------------------
| 3  | s_1       | t_2         |
--------------------------------
| 4  | t_1       | s_2         |
--------------------------------

对不起表格看起来我不知道如何做得更好。

我希望只允许教师或学生的值存储在messages.sender_id和messages.receiver_Id中,就像FK一样。

我需要知道是否可能,如果可能,怎么样?

2 个答案:

答案 0 :(得分:1)

您有两种不同的选择。 首先是创建一个Person表,另一个是PersonType。 PersonType将包含"学生"和#34;老师"作为价值观。将PersonTypeId添加到Person并为PersonType创建外键,这将作为学生和教师之间的鉴别器。将外键添加到Person的Messages表中。

第二个是创建"数据库继承"。使用学生和教师之间的公共数据创建Person表。然后,使用每个的特定数据创建“学生和教师”表,并在两者上添加外键。将您的外键添加到来自Person表的消息。 第一种解决方案更具性能。

答案 1 :(得分:0)

MySQL不支持声明性外键约束来强制执行此完整性规则。使用所示的表(即不更改表),我们可以使用触发器来强制执行这些类型的参照完整性规则。它需要在所有三个表上组合BEFORE INSERT,BEFORE UPDATE,BEFORE DELETE触发器。

我们没有看到任何会阻止相同值(例如k_9)出现studentteacher表格的规则。因此,sender_ID的邮件中的一行是k_9,我们无法确定引用的内容,studentteacher或两者。

如果可以更改表定义,我们可以将person表实现为studentteacher的超类。实现这一点的几种模式。一种可能性是添加鉴别器列。

person
ID    type     name
---   -------  ------
s_1   student  Lukas
s_2   student  Oliver
t_1   teacher  Dani
t_2   teacher  Billy
k_9   student  Rover

使用该表,从messages声明外键约束将是直截了当的。

我们可以在原始设计中返回students表和teachers表的等价物:

SELECT ID, name FROM person WHERE type = 'student'

教师

SELECT ID, name FROM person WHERE type = 'teacher'

但是只给出问题中显示的三个表,就不可能声明外键约束来强制执行指定的引用完整性规则。执行这些完整性规则的唯一方法是通过触发器。

BEFORE INSERT ON messages
FOR EACH ROW
BEGIN
   -- if NEW.sender_ID is non-NULL, verify the value appears
   -- as value in `ID` column of either `students` or `teachers`
   -- if not, throw an error 

   -- if NEW.receiver_ID is non-NULL, verify the value appears 
   -- as value in `ID` column of `students` or `teachers`
   -- if not, throw an error 

END

我们还需要UPDATE ON消息的触发器,以及UPDATE和DELETE ON学生和教师