这样的空值可以吗?
这是主观的。问题是:你能用它吗?可能是。但它能保证完整性吗?没有。
那么会出什么问题呢?您可以设置两个外键,也可以同时保留 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_id 和 user_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 是为了什么?通常您有多个目标,例如 clearness、simplicity、usability、flexibility、reliability ,性能,可能还有更多。灵活性的“最佳方法”可能是性能的噩梦,反之亦然。
一个更广泛使用的术语是“良好实践”。 数据库规范化被认为是良好的实践。添加user_id 和client_id 会在非candidate key 上引入功能依赖,这违反了3NF。
另一方面,如果没有这些列,您需要在 SELECT 查询中再加入一个 JOIN。但只要它不重要,我不会太在意。