2010-01-07 57 views
5

我有如下表:与外键约束相关的表使用空值的

Cateogories

  • 类别ID(int)的主键
  • 类别名称(VARCHAR)

项目

  • ITE MID(INT)主键
  • 类别ID(INT)
  • ITEMNAME(VARCHAR)

有上Items.CategoryID外键约束。有一种可能性,即在创建新项目时不会分配类别。

将Items.CategoryID设置为允许空值并处理我的代码中的空值或者最好不允许空值,将默认的CategoryID设置为1并在Categories表中创建一个名为“Uncategorized”的虚拟记录,然后在我的代码中处理这个虚拟类别?

+0

我原本应该发布一个项目只能在一个类别中。 – jpshook 2010-01-07 14:47:36

+0

相关:http://stackoverflow.com/questions/2016730/column-nullability-optionality-null-vs-not-null – 2010-01-08 02:51:25

回答

6

逻辑上正确的方法是对CategoryID列是NULL当没有该项目类别。

如果获得任何与使用NULL相关的陷阱被困,那么最有可能的是,设计处理不当所采取的事实,项目不能有一类帐户的迹象。修复设计。 NULL将确保您坚持解决正确的问题。

+0

即使该类别为“杂项”或类似,此上下文中的项目也将始终具有类别。只有当字段具有无数据状态的逻辑可能性时才应使用NULL,例如一个还活着的人的死亡日期。 – melkisadek 2010-01-07 14:10:15

+1

海报说有时候某个物品没有分类。这与其他杂项或其他虚拟类别不同。 你有一些我不知道的信息吗? – 2010-01-07 14:20:28

+1

另一个允许NULL无类别的理由 - 如果您有下拉列表的类别,那么用户将最终看到这个虚拟类别,除非您硬编码从下拉列表中排除它,无论如何需要特殊编码。 – 2010-01-07 14:30:03

0

SQL NULLs are tricky,所以我觉得你是一个类别定点更好。

+0

几乎列表中的每个项目符号都很容易在数学上解释和/或**是**解释在SQL规范中。这是一个回答问题的网站,不会发布关于标准规格如何不按照您认为应该的方式工作的抱怨。 – Aaronaught 2010-01-07 14:34:36

+0

我不需要抱怨标准 - 总体上非常有用的标准 - 但公平地说,应该避免它的某些部分。 “易于数学解释”,这部分不是。 – Tobu 2010-01-07 15:01:44

+1

NULL ANSI规范不一致,通常被认为是中断的。大多数认为他们理解NULL的开发人员确实没有。 – KenFar 2010-01-07 20:42:40

0

在这种情况下,我认为这确实是个人偏好的问题。无论哪种方式,你都必须处理代码中未分类的项目。

1

理想情况下,你会希望允许创建一个项目之前,迫使一个类别的选择。如果一个项目将来没有任何类别,那么您需要专门创建一个类别来处理这个类别。我个人不会称之为“未分类”,因为这意味着用户可以稍后追赶它 - 他们会忘记做出惊人的规律!

寻求逻辑一致性,否则你最终会陷入混乱。如果这意味着创建一个“杂项”类别,那么做到这一点,并确保(a)用户知道何时使用它和(b)定期报告以确保项目正确分类。

2

这取决于:

如果您的项目真的没有类别,然后我会允许NULL S,因为这是你拥有的一切:没有类别编号。

如果要列出所有类别,你不希望显示的虚拟行,所以你必须忽略。

如果要显示所有项目并显示类别,最好注意有没有类别的项目,所以在这种情况下您将使用LEFT JOIN

如果可能,请在实际保存项目之前更改您的应用程序以选择一个类别。


如果你想治疗是Uncategorized类别就像其他类别(与其他类别一一列举了,算分配给它的项目,在列表/下拉列表中选择它),那么它应该得到它自己的类别, Item.CategoryId应该是NOT NULL

0

我不相信任何一种选择都很好。

如果您选择NULL方法,您将遇到涉及使用NULL的陷阱问题。如果您选择不允许使用空值,则需要处理如果您删除项目将级联的类别的情况。

IMO最好的设计是有三张桌子。

Categories 
ID 
Name 

Items 
ID 
Name 

Categories2Items 
CategoryID 
ItemID 

这消除了对NULL的需求(以及所涉及的陷阱),它属于几个类别,以及可以让你有未分类的项目,项目。这种设计也是Boyce-Codd Normal形式,总是一件好事.. en.wikipedia.org/wiki/BCNF

+1

然后你得到每个项目的多个类别,称他们的标签。这是一个很好的设计,但是OP想要什么? – Tobu 2010-01-07 14:23:40

+0

我应该提到,在这种情况下,它是一对一的物品类别。您的答案适用于多方面的情况。对于一对一,这会使SQL复杂化,并要求您在应用程序中强制执行一对一(凌乱)。我原来的设计至少有效3NF。 – jpshook 2010-01-07 14:45:58

+0

是的,我知道。但设计是可扩展的,并消除了两种设计中的许多问题。此外,如果我可能是一个挑逗,类别不是每个定义不相交。 但是,如果这不是OP想要的,那么选择NULL方法显然比拥有一个哨兵类别更好。删除某个项目所属的类别将要求CASCADE删除该项目,这可能不是一件好事,会触发并非所有DBMS都支持或者将类别ID保留为空值。然后,OP将在其数据库中包含NULL分类和未分类项目。 – 2010-01-07 14:53:24

1

对于这种类型的简单查找表,几乎总是禁止NULL并在查找表中有未知值。

为什么?

  • 由于ANSI NULL规范不一致且非常复杂。处理空值大大增加了编码缺陷的可能性,并且需要更多的代码来编写
  • 由于很少开发人员真正了解NULL在所有场景中的工作原理
  • 因为它简化了您的模型并且很好地查询。使用非常简单的sql,您可以将任何方向的内部连接很好地结合在一起。

然而,一些注意事项:

  • 您可能需要不止一个“虚拟”的价值更多:一为“未知”,另一个是“未分配”。当然,NULL绑定到一个单一的值,所以如果你这样做,你会超出最低标准超过&。
  • 您最终有时会得到额外的非关键属性,这些关键属性必须是可以为空或者对于虚拟行携带'n/a'类型值。对于严重非规格化的查找表(如仓储维度),您可能希望空值允许使用这些列,因为'n/a'不适用于时间戳,金额等。
  • 如果您将此技术应用于更多简单的查找表会大大地让你的设计复杂化。不要这样做。