具有可为空外键的数据库 table
Database table with nullable foreign key
我正在为我的网站创建一个新的数据库设计。我的数据库中有两种类型的用户。所以我有 user_t 并且它与 client_t 相关联。一个用户可以有多个客户端。现在我有 app_t。一个客户可以拥有多个应用程序。
这个app_t可以由客户端和用户更新。我正在为 app_t 创建审核试验 table,我不想在 updated_by[=27= 中存储名称] 因为它可能会改变。相反,我想将 client_id 和 user_id 作为列。在这种情况下,当客户端更新 table user_id 列时将为空,而当用户更新 table client_id 将为空。这两个 id 都是外键,它们引用各自 table 的主键列。有这样的空值可以吗?
提前致谢。
Is it okay to have such null values?
这是主观的。问题是:你能用它工作吗?可能是。但是能保证完整性吗?编号
那么会出什么问题呢?您可以设置两个外键,也可以同时保留两个 NULL - 数据库不会抱怨。在这两种情况下,您都不知道谁更新了该项目。
另一种方法是始终设置 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
但事情仍然可能出错。您可以保存不是应用程序 "owner" 的客户的 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 approach" 或 "best practice" 这样的东西,当问题是 "complex enough" 时。那么问题是 - Best 有什么用?通常您有多个目标,例如 清晰度、简单性、可用性、灵活性、可靠性、性能,可能还有更多。灵活性的 "best approach" 可能是性能的噩梦,反之亦然。
一个更广泛使用的术语是“良好实践”。 数据库规范化被认为是好的做法。添加 user_id
和 client_id
在非 candidate key, which violates 3NF.
上引入 功能依赖性
另一方面,如果没有这些列,您需要在 SELECT 查询中再添加一个 JOIN。但只要不是很重要,我就不会太在意。
我正在为我的网站创建一个新的数据库设计。我的数据库中有两种类型的用户。所以我有 user_t 并且它与 client_t 相关联。一个用户可以有多个客户端。现在我有 app_t。一个客户可以拥有多个应用程序。
这个app_t可以由客户端和用户更新。我正在为 app_t 创建审核试验 table,我不想在 updated_by[=27= 中存储名称] 因为它可能会改变。相反,我想将 client_id 和 user_id 作为列。在这种情况下,当客户端更新 table user_id 列时将为空,而当用户更新 table client_id 将为空。这两个 id 都是外键,它们引用各自 table 的主键列。有这样的空值可以吗?
提前致谢。
Is it okay to have such null values?
这是主观的。问题是:你能用它工作吗?可能是。但是能保证完整性吗?编号
那么会出什么问题呢?您可以设置两个外键,也可以同时保留两个 NULL - 数据库不会抱怨。在这两种情况下,您都不知道谁更新了该项目。
另一种方法是始终设置 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
但事情仍然可能出错。您可以保存不是应用程序 "owner" 的客户的 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 approach" 或 "best practice" 这样的东西,当问题是 "complex enough" 时。那么问题是 - Best 有什么用?通常您有多个目标,例如 清晰度、简单性、可用性、灵活性、可靠性、性能,可能还有更多。灵活性的 "best approach" 可能是性能的噩梦,反之亦然。
一个更广泛使用的术语是“良好实践”。 数据库规范化被认为是好的做法。添加 user_id
和 client_id
在非 candidate key, which violates 3NF.
另一方面,如果没有这些列,您需要在 SELECT 查询中再添加一个 JOIN。但只要不是很重要,我就不会太在意。