【问题标题】:Database table with nullable foreign key具有可为空外键的数据库表
【发布时间】:2019-08-12 15:07:06
【问题描述】:

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

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

提前致谢。

【问题讨论】:

  • 可以删除用户或客户端吗?
  • @PaulSpiegel 不,我们从不删除

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


【解决方案1】:

这样的空值可以吗?

这是主观的。问题是:你能用它吗?可能是。但它能保证完整性吗?没有。

那么会出什么问题呢?您可以设置两个外键,也可以同时保留 NULL - DB 不会抱怨。在这两种情况下,您都不知道是谁更新了该项目。

另一种方法是始终设置user_id (NOT 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 是为了什么?通常您有多个目标,例如 clearnesssimplicityusabilityflexibilityreliability性能,可能还有更多。灵活性的“最佳方法”可能是性能的噩梦,反之亦然。

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

另一方面,如果没有这些列,您需要在 SELECT 查询中再加入一个 JOIN。但只要它不重要,我不会太在意。

【讨论】:

  • 感谢@PaulSpiegel 的回复。这么晚才回复很抱歉。我们有同样的想法,只有 app_id 关联,然后有一个标志来表示它是客户端还是用户。但是我们不确定这是否是最佳实践,因为我们是数据库设计的新手。如果您真的觉得这是最好的方法,我会继续并将其标记为已回答。
  • @sureshbabu 我的回复太长,无法发表评论 - 所以我更新了答案。
  • 你能帮忙解决这个问题吗stackoverflow.com/questions/55501603/…
  • 如果不能保证完整性,为什么还要声明 FK??
猜你喜欢
  • 2011-10-23
  • 1970-01-01
  • 1970-01-01
  • 2020-10-04
  • 2013-05-03
  • 2011-12-04
  • 1970-01-01
  • 1970-01-01
  • 2021-10-26
相关资源
最近更新 更多