Nullable column vs Special Default row用于从其他表引用 - 哪种设计更好?

时间:2014-07-01 22:41:51

标签: sql sql-server database database-design

需要有关2 DB设计的建议

假设我们有2个表ArtefactUser。 Artefact引用了创建它的用户。但是在我们的遗留系统中很长一段时间,这个引用被存储为一个字符串名称,所以现在它不可能为所有人工制品恢复创建者(来自User表的一些相应记录已经消失)。 因此,有两种选择:

  1. Artefact表创建一个可为空的UserId列,并为已经删除了创建者的人工制品填充null。
  2. 创建一个特殊的默认记录' Non Exsisting User'在User表中,并从Artefact表中引用所有包含未知创建者的记录。
  3. 目前我想知道哪个选项更好?

    第二种方法的优点

    1. 更简单的sql谓词(没有无尽的isnull()left joins
    2. 更一致的解决方案 - Artefact实体始终拥有父User,您可以依赖
    3. 第二种方法的缺点

      1. 违反奥卡姆剃刀并引入非自然和不存在的业务对象'不存在用户
      2. 在我的整个职业生涯中都没有遇到过这种方法(这可能不是一个很好的标志,因为所有伟大的想法通常都有一些应用的历史)。
      3. 所以,我想知道关于上述两种数据库设计方法的任何其他优点和缺点,以便在我的案例中做出更好的决定。

1 个答案:

答案 0 :(得分:1)

重申第二种方法的优点:

  
      
  1. 更简单的sql谓词(没有无尽的isnull()left joins
  2.   

不幸的是,你仍然有另一种无穷无尽的习语:用户<> '非现有用户'。 (在Artefact和User之间加入时,唯一的节省就是LEFT这个词。)

  
      
  1. 更一致的解决方案 - Artefact实体始终拥有父User,您可以依赖
  2.   

但SQL允许在非空时检查从Artefact(用户)到User的外键。

简单的关系设计是有一个单独的表:

ArtefactUser(artefact, user)  
    pk (artefact, user)  
    fk artefact references Artifact not null
    fk (user) references User not null

你可能会对此感到满意。然后,保存连接的简单SQL版本是让用户成为Artefact中的可空列。这是您的选择1.

你必须要注意使用null的习惯用法(因为SQL 3VL并发症)将它们尽可能地移到查询表达式的叶子附近。

重申其缺点:

原则上在列中有特殊值没有错。但在SQL中,没有数据类型支持这样做。

例如:我们不希望“非现有用户”#39;永远被视为用户名。因此,让User user为varchar(n)并且Artefact用户为varchar(n)U {non_existing_user}会很高兴,其中non_existing_user是某个值/ token / enum,与任何字符串不同。并且对FK的相应约束将是(select user from Artefact where user<>non_existing_user) <= (select user from User)。 SQL中最接近的是使用空值。但是NULL在查询中不作为正常值处理。 (也不像任何意义&#34;未知&#34;或&#34;不适用&#34;。)

例如:在您的邮件和评论中,您一直拼错了“非现有用户”#39; (还有&#34;神器&#34;。)没有类型检查。

所涉及的两列确实接受不同的值集。除此之外,如果NULL不涉及3VL,那么它只是一个不是任何类型的值,但是列也可以保持。这基本上是你的选择2.所以做选项2并不可怕。(用户应该被限制为拥有用户&lt;&gt;&#39;非现有用户&#39;。)

在其他类型和其他目的中,并不总是特别使用的值。

(别忘了考虑选择单独的表格。)