代码之家  ›  专栏  ›  技术社区  ›  Tarzan

除了NULL之外,处理未知日期时间值的好策略是什么?

  •  1
  • Tarzan  · 技术社区  · 11 年前

    我的数据库有3个表:Organization、User&组织用户连接。OrganizationUserJunction表跟踪用户属于哪个组织、何时成为组织成员以及何时离开组织。MemberFrom字段填充有已知日期,但MemberTo日期起初未知。我不喜欢在表中使用NULL值。

    当我处理字符串字段时,我可以用“UNKNOWN”而不是NULL填充它们。我想对日期时间列做一些类似的事情。除了null之外,处理具有未知值的SQL Server日期时间列的好策略是什么?

    6 回复  |  直到 11 年前
        1
  •  4
  •   nvogel    11 年前

    以你所描述的为例。当前成员没有MemberTo日期,因此在成员资格表中,您不需要MemberTo日期。将MemberTo日期放在前成员的表中(该表将包含此属性以及与不适用于当前成员的前成员身份关联的其他属性)。这样做不需要null。

        2
  •  3
  •   Mike Sherrill 'Cat Recall'    11 年前

    其他人没有提到的另一种选择是对两个日期列使用单独的表。(在重新阅读时,我看到无与伦比的@sqlvogel确实提到了这一点。我将把代码作为一个示例。如果@sqlvoge想把它合并到他的答案中,我刚刚投了赞成票,这对我来说没问题。我稍后会删除我的答案。)

    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)
    );
    
        3
  •  2
  •   Neil McGuigan    11 年前

    这是一个合理的问题,我不确定你为什么被否决。

    至少根据Joe Celko的说法,正确的答案是使用9999-12-31作为结束日期。根据ISO 8601,这是正式的“时间的终结”。

    您也可以考虑使用第六个法线形式(也称为锚点建模),它是为此目的而设计的。

        4
  •  1
  •   Aaron Bertrand    11 年前

    怎么了 NULL ? 如果实际原因是 无效的 很重要(例如心率 无效的 因为他已经死了,或者因为我们还没有捕捉到它),在单独的专栏中追踪它(也许是 tinyint FK已添加到名为 dbo.DateIsNULLReasons 表)。

    对此的所有解决方法(“神奇”日期值,对所有日期使用INT,查找到必须具有 无效的 可以在那里写专栏或存储一个神奇的日期)对我来说似乎是黑客。

    我认为你应该克服你对 无效的 s。它们的存在是有原因的,例如指定值为 unknown ,不管你喜欢与否,也不管是什么原因。

    你通过储存获得了什么 UNKNOWN 而不是 无效的 ? 你知道在表和任何二级索引中需要花费多少额外空间吗?您现在必须针对某些查询过滤掉该场景,这难道不令人讨厌吗?

        5
  •  1
  •   Lymedo    11 年前

    使用默认日期进行成员审核如何。比如说加入后5年。

    或者,如果我们与一家商业组织打交道,并且您记录了出生日期和性别,那么您可以计算退休年龄。

    就我个人而言,我认为NULL没有问题。在MemberTo date的上下文中,IS NULL=仍然是成员。它的作用与默认值完全相同,并且远没有填充默认日期值那么复杂。

        6
  •  0
  •   Boolean_Type    4 年前

    我知道这是一条古老的线索,但我偶然发现了它。

    这是一个很好的观点 null 应该避免,尤其是 DateTime .

    原因 :SQL server默认值 无效的 类似于 1/1/1900 。如果你有这样的用例 dateOfCasuality ,那么您需要包含特殊的逻辑来处理DOB相关的规则。

    可能的解决方案 :使用 ForeignKey 与另一个包含日期的表的关系。但这会增加模式的复杂性。然而,我永远不会试图把它变成一个字符串,因为这会导致一场编码噩梦。