如果我不想使用 NULL,我将如何规范化这个 table?

If I wanted to not use NULL, how would I normalize this table?

line_item (id, description, parent_id, product_id);
product (id, model);

订单项层次结构示例

Product A       //"parent" "line item"
    Option 1    //child "line item"s of "parent"
    Option 2    

当前数据库数据

line_item:
id | description | parent_id | product_id
-----------------------------------------
 1 |   Product A |      NULL |         20  //has no parent "line item"
 2 |    Option 1 |         1 |         -1  //no product associated with option
 3 |    Option 2 |         1 |         -1  //has "line item" parent with id == 1
product
id | model
--------------
20 | Product A

问题

我不太确定如何从 parent_id 中删除 "NULL"。请注意,我也在我的 product_id 中使用 -1,我以类似的方式使用它,说 "there is no "product" 或 "parent" 与该特定订单项记录相关联。

需要首先摆脱它吗?

NULL 是表示无值的正确方法。

此外,为了获得良好实践,如果您在字段 parent_id 上添加引用父项 line_item 的外键,或者 product_id 引用您无法使用的产品 - 1.

我认为您希望保留 NULL 完整,因为它可以用作指示哪些记录是顶级项目的指标。此外,表格似乎已经规范化,因此规范化与您的问题无关。

首先,您应该将-1 替换为null。这是一个完全合法的值。

在考虑归一化时,空值实际上不起任何作用,因为如果你有非空值,你只能谈论函数依赖,所以你不必担心归一化,你的 table 没问题。

您的 table 是 "disjunct is-a" 关系的实现,这意味着 line_item 是 "option" 行(值为 parent_id) 或 "product" 行(值为 product_id 和例如 quantity, ...)并且具有共同的值 iddescription . Disjunct 意味着它不能同时存在,因此其他类型的列设置为空(这就是为什么你 "have to" 将 -1 替换为空)。

"disjunct is-a" 的通常实现是添加一个 type 列,它定义了这些可能性中的哪一种(原因更实际,例如约束检查).你在这里不需要它,因为你很清楚没有这个字段它是什么样的行,但我添加它是为了强调你实际实现的是什么并且你以标准方式完成了所有事情:

line_item:
id | description | line_type | parent_id | product_id
-----------------------------------------------------
 1 |   Product A |   Product |      NULL |         20  
 2 |    Option 1 |    Option |         1 |       NULL  
 3 |    Option 2 |    Option |         1 |       NULL  

最后的评论:"is-a"还有其他可能的实现,其中一些正在摆脱空值(同时引入其他问题),但对于分离选项,这是通常的实现。但是因为它会回答你原来的问题 ("If I wanted to not use null..."),所以我也会添加这个:

line_item:
id | description 
-----------------
 1 |   Product A 
 2 |    Option 1 
 3 |    Option 2 


line_item_product:
line_item_id | product_id
---------------------------
           1 |         20  

line_item_option:
line_item_id |  parent_id
---------------------------
           2 |          1 
           3 |          1 

你有一个 table 用于公共列(对于两种类型 optionproduct)和一个单独的 table 用于两种可能性及其特定列。

这将消除您的 null。

最大的实际问题是,您必须对 table 和 line_item_product 这两个 table 中的 "primary key" 进行更复杂的检查:当第 1 行已经在 line_item_product 中时,您不能在 line_item_option 中添加它,但是 mysql 对此没有简单的检查。这就是为什么这种拆分仅在您具有 "non-disjunct is-a" 关系时使用(例如,如果这些行可以同时是产品和选项)。