我的数据库有 3 个表:组织、用户和组织用户连接。OrganizationUserJunction 表跟踪用户所属的组织、他们何时成为该组织的成员以及何时离开该组织。MemberFrom 字段填充了一个已知日期,但 MemberTo 日期一开始是未知的。我不喜欢在我的表中有 NULL 值。
当我处理一个字符串字段时,我可以用“未知”而不是 NULL 填充它们。我想对日期时间列做类似的事情。除了空值之外,还有什么好的策略来处理具有未知值的 SQL Server 日期时间列?
我的数据库有 3 个表:组织、用户和组织用户连接。OrganizationUserJunction 表跟踪用户所属的组织、他们何时成为该组织的成员以及何时离开该组织。MemberFrom 字段填充了一个已知日期,但 MemberTo 日期一开始是未知的。我不喜欢在我的表中有 NULL 值。
当我处理一个字符串字段时,我可以用“未知”而不是 NULL 填充它们。我想对日期时间列做类似的事情。除了空值之外,还有什么好的策略来处理具有未知值的 SQL Server 日期时间列?
以您描述的示例为例。当前成员没有 MemberTo 日期,因此在成员资格表中您不需要 MemberTo 日期。将 MemberTo 日期放在前成员的表中(该表将包含此属性以及与前成员相关的其他属性,但不适用于当前成员)。不需要空值来执行此操作。
没有其他人提到的另一种方法是为两个日期列使用单独的表。(在重新阅读时,我看到无与伦比的@sqlvogel 确实提到了这一点。我将代码作为示例。如果@sqlvogel 想将它合并到我刚刚赞成的答案中,那对我来说很好。我会之后删除我的答案。)
create table org_users (
org_id integer not null references organizations (org_id),
user_id integer not null references users (user_id),
member_from date not null default current_date,
primary key (org_id, user_id, member_from)
);
create table org_users_member_to (
org_id integer not null,
user_id integer not null,
member_from date not null,
member_to date not null default current_date
check (member_to > member_from),
primary key (org_id, user_id, member_from),
foreign key (org_id, user_id, member_from)
references org_users (org_id, user_id, member_from)
);
这是一个合理的问题,我不确定你为什么被否决。
至少根据 Joe Celko 的说法,正确答案是使用 9999-12-31 作为您的结束日期。这是根据 ISO 8601 的官方“时间结束”。
您还可以考虑使用为此目的而设计的第 6 范式(又名 Anchor Modeling)。
有什么问题NULL
?如果它的实际原因很NULL
重要(例如,心率是NULL
因为他死了,或者因为我们还没有捕获它),请在单独的列中跟踪它(可能是一个tinyint
FK 到一个名为dbo.DateIsNULLReasons
table 的查找表)。
对此的所有解决方法(“魔术”日期值,对所有日期使用 INT 来查找必须具有NULL
有效列或在其中存储魔术日期的不同表)对我来说似乎是黑客行为。
我认为你应该克服你对NULL
s的厌恶。它们的存在是有原因的,例如指定值为unknown
,无论您喜欢与否,以及无论原因如何。
通过存储UNKNOWN
而不是存储可以获得什么NULL
?您知道在表和任何二级索引中花费了多少额外空间吗?您现在必须为某些查询过滤掉该场景,您不觉得烦人吗?
使用默认日期进行会员审核怎么样?加入5年后再说。
或者,如果我们正在与一个商业组织打交道并且您捕获 DOB 和性别,那么您可以计算退休年龄。
我个人认为 NULL 没有问题。在 MemberTo date 的上下文中,IS NULL = 仍然是成员。它与默认值的用途完全相同,并且远没有填充的默认日期值复杂。
我知道这是一个旧线程,但我偶然发现了它。
这是一个null
应该避免的好点,尤其是对于DateTime
.
原因:SQL 服务器默认null
为1/1/1900
. 如果您有类似的用例dateOfCasuality
,则需要包含特殊逻辑来处理 DOB 相关规则。
可能的解决方案:使用ForeignKey
与另一个包含日期的表的关系。但这会增加模式的复杂性。但是,我永远不会尝试将其转换为字符串,因为这会导致编码噩梦。