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

时间:2016-05-10 20:14:16

标签: mysql sql database null database-normalization

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

问题

我不确定如何摆脱" NULL"来自parent_id。请注意,我在我的-1中使用了product_id,我也以类似的方式使用#!/usr/bin/ruby require 'softlayer_api' client = SoftLayer::Client.new(username: 'USER', api_key: 'APIKEY') productOrder = { 'virtualGuests' => [{ 'hostname' => 'test', 'domain' => 'mycompany.com', 'primaryBackendNetworkComponent' => { 'networkVlan' => { 'id' => XXXXX } } }], 'location' => XXXXX, 'packageId' => 46, 'imageTemplateId' => XXXXX, 'useHourlyPricing' => true, 'prices' => [ {'id' => 26125 }, # 1 x 2.0 GHz Core {'id' => 32597 }, # 1 GB RAM {'id' => 23065 }, # 100 GB (SAN) {'id' => 23065 }, # 100 GB (SAN) {'id' => 34183 }, # 0 GB Bandwidth {'id' => 24713 }, # 1 Gbps Public & Private Network Uplinks {'id' => 34807 }, # 1 IP Address {'id' => 33483 }, # Unlimited SSL VPN Users & 1 PPTP VPN User per account {'id' => 34241 }, # Host Ping and TCP Service Monitoring {'id' => 32500 }, # Email and Ticket {'id' => 35310 }, # NESSUS_VULNERABILITY_ASSESSMENT_REPORTING {'id' => 23070 }, # REBOOT_REMOTE_CONSOLE {'id' => 32627 } # AUTOMATED_NOTIFICATION ] } order = client['Product_Order'].verifyOrder(productOrder) here ,说"没有"产品"或者"父母"与该特定订单项记录相关联。

首先我需要摆脱它吗?

3 个答案:

答案 0 :(得分:1)

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

此外,对于良好实践,如果在引用父line_item或product_id引用产品的字段parent_id上添加外键,则无法使用-1。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

首先,你应该用null替换-1。这是完全合法的价值。

在考虑规范化时,空值实际上不起作用,因为如果你有非空值,你只能说功能依赖,所以你不必担心规范化,你的表很好。

你的表是“disjunct is-a”关系的实现,这意味着line_item是“选项”-line(值为parent_id)或“product”-line (值为product_id,例如quantity,...),并且具有公共值iddescription。 Disjunct意味着它不能同时存在,所以另一个类型的列被设置为null(这就是为什么你“必须”将null替换为null)。

“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”实现,其中一些是摆脱null(同时引入其他问题),但对于disjunct选项,这是常见的。但既然它会回答你原来的问题(“如果我不想使用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 

您有一个用于公共列的表(适用于optionproduct两种类型)和一个单独的表,用于表示具有特定列的两种可能性。

这将摆脱你的空。

最大的实际问题是,您必须对两个表line_item_optionline_item_product中的“主键”进行更复杂的检查:不允许添加第1行在line_item_option中它已经在line_item_product中,但是mysql没有那么容易检查。这就是为什么只有当你有一个“非分离是一个”关系时才使用这种分裂(例如,如果这些行可以同时是产品和选项)。