具有可空外键的数据库表

时间:2019-03-21 17:17:13

标签: mysql database-design relational-database audit-trail

我正在为我的网站创建一个新的数据库设计。我的数据库中有两种类型的用户。因此,我有 user_t ,并且它与 client_t 相关联。一个用户可以有多个客户端。现在,我有 app_t 。一个客户端可以有多个应用程序。

app_t 可以由客户端和用户进行更新。我正在为 app_t 创建审核试用表,我不想在其中将名称存储在 updated_by 中,因为名称可能会更改。相反,我想将 client_id user_id 作为列。在这种情况下,当客户端更新表 user_id 列时将为空,而当用户更新表 client_id 时将为空。这两个id都是外键,它们引用各个表的主键列。拥有这样的空值可以吗?

谢谢。

1 个答案:

答案 0 :(得分:2)

  

可以有这样的空值吗?

这是主观的。问题是:您可以使用它吗?可能是。但是可以保证完整性吗?不。

那怎么可能出问题呢?您可以设置两个外键,也可以都设置为NULL-数据库不会抱怨。无论哪种情况,您都不知道是谁更新了该项目。

另一种方法是始终设置user_id(不为NULL),并使client_id为可选。如果client_id为NULL,您知道-它由用户更新。如果它不是NULL,那么您知道-它由客户端更新。

然后您可以使用以下方法检索名称:

select at.*, coalesce(c.name, u.name) as updated_by
from app_audit at
join user_t u        on u.id = at.user_id
left join client_t c on c.id = at.client_id

但是事情仍然可能出错。您可以保存不是该应用程序“所有者”的客户端的ID。 user_id也是如此。由于设计(审核跟踪->应用程序->客户端->用户),client_iduser_id在功能上都依赖于app_id。因此,实际上您只需要app_id作为外键和一个布尔型标志即可告诉您它是由用户还是由客户端更新的。然后,您将使用以下方法检索数据:

select at.*, coalesce(u.name, c.name) as updated_by
from app_audit at
join app_t a       on a.id = at.app_id
join client_t c    on c.id = a.client_id
left join user_t u on u.id = c.user_id  and a.updatet_by_user = 1

关于您的评论:

当问题“足够复杂”时,我不相信诸如“最佳方法”或“最佳实践”之类的东西。那么问题是- Best 是什么?通常,您有多个目标,例如清除简单性可用性灵活性可靠性性能,甚至更多。灵活性的“最佳方法”可能是性能的噩梦,反之亦然。

更广泛使用的术语是“ 良好实践”。而数据库规范化被认为是良好实践。添加user_idclient_id会在非candidate key上引入功能上的依赖关系,这违反了3NF

另一方面,如果没有这些列,则在SELECT查询中还需要一个JOIN。但是只要它不重要,我就不会在意。