如何选择主键并规范化这种关系模式?

时间:2017-11-07 21:05:52

标签: sql primary-key database-normalization third-normal-form

假设我有一个包含以下属性的表

  • 订单ID
  • item id
  • 料品数量
  • 商品单价
  • 项目付款

其中“项目付款=项目单价x项目数量”。 让我们简化一下情况,并假设每个订单只有一个商品ID的数量,不同的订单可能具有相同的商品ID。

  1. 什么是主键,“订单ID”,“订单ID”和“商品ID”,或 别的什么?
  2. 如何将其归一化为3NF?

    以下是我正在考虑的解决方案:

    • 包含订单ID(主键),料品ID,料品数量和料品付款的表格

    • 包含商品ID(主键和上一个表的外键)以及商品单价的表格。

  3. 继续我在第2部分中给出的暂定解决方案。在第一个表格中,对于每个项目ID,项目付款是 与物品数量成比例。如果是第一个表的主键 是订单ID,项目付款取决于非主键属性项目数量,其中 违反了3NF要求,没有传递性。

    我应该将第一张表分成:

    • 包含订单ID(主键)和商品ID
    • 的表格
    • 包含商品ID的表(主键和之前的表的外键),商品数量和商品付款

    或进入:

    • 包含订单ID(主键)和商品ID
    • 的表格
    • 包含商品单价(主键和原始第二张表的外键),商品数量和商品付款的表格?
  4. 感谢。

4 个答案:

答案 0 :(得分:2)

您应该有一个以OrderID作为主键的表。这是因为您可能具有在顺序上具有非平凡功能依赖性的属性(例如,order_date,order_status,CustomerID),这些属性不依赖于顺序中的行。

您还应该再次拥有一个表,其中ItemID是主键。同样,它将具有对ItemID具有功能依赖性的属性(例如描述,价格等)

最后你会有第三张桌子。该表将具有Order和Item的外键。这些键表示候选复合键。您可以使用它或创建代理主键OrderItemID。如果您确实创建了代理键,我仍然会确保创建一个唯一键(OrderID,Item)。

     +----------------+         +----------------+
     |  OrderID       |         |    ItemID      |
     +----------------+         +----------------+
     |  CustomerID    |         |   Description  |
     |  OrderDate     |         |   Price        |
     |  Status        |         +----------------+
     |  Payment       |                       |
     +----------------+                       |
            |                                 |
            |                                 |
            |       +---------------------+   |
            |       |   OrderItemID       |   |
            |       +---------------------+   |
            +-------+   OrderID  FK U1    +---+
                    |   ItemID   FK U1    |
                    |   Quantity          |
                    +---------------------+

答案 1 :(得分:2)

我们不要在开始时谈论ID ......

  1. 有订单。订单通常有一个订单号,您可以在发票上打印等。订单有订单日期,供应商是关于您与供应商或客户订购的订单,这是关于您的客户与您订购的订单。
  2. 有些商品可以订购。物品有一个物品编号,例如GTN(全球贸易编号)。物品有不同日期,不同客户等的名称和价格甚至价格表。
  3. 订单通常可以包含多个项目,例如5件商品A和10件商品B.这​​些是包含商品,数量和价格的订单位置。
  4. 这可能是表格(主键粗体,唯一列斜体):

    • 客户端( client_number client_name
    • 项目( item_number item_name ,价格)
    • 订单( order_number ,order_date,client_number)
    • order_position( order_number,item_number ,金额,价格)

    您不会存储单个价格和金额以及总价格,因为这将是多余的。避免在数据库中出现冗余,因为这会导致很多问题。

    您可以在表格中使用技术ID。您可以将这些表作为主键,但是您必须仍然存储上面提到的所有数据,之前的主键是一列或一组定义为非可空且唯一的列,这实际上是与主键相同:

    表格(主键粗体,唯一列斜体):

    • 客户端( client_id client_number client_name
    • 项目( item_id item_number item_name ,价格)
    • 订单( order_id order_number ,order_date,client_number)
    • order_position( order_position_id order_id + item_id ,金额,价格)

答案 2 :(得分:1)

这看起来像一个订单行。通常,您有一个订单ID和订单行号的主键。 item id应该是你的items表中的一个外键,它应该有价格,但除非你永远不给折扣,否则你的订单行也应该有价格。

如果您允许部分付款并希望在该级别跟踪,则支付订单行的金额是可以的。

答案 3 :(得分:0)

通过你的名字猜测&常识,表的3NF分解是

-- order order_id requests item item_id in quantity item_quantity
order_has_item_in_quantity(order_id, item_id, item_quantity)

-- item item_id has unit price item_unit_price
item_has_unit_price(item_id, item_unit_price)

--     some order requests some item in quantity item_quantity
-- and that item has unit price item_unit_price
-- and item_unit_price * item_quantity = item_payment
unit_price_and_quantity_has_payment(item_unit_price, item_quantity, item_payment)

但是,如果您已经可以访问在SQL查询中执行的乘法表(这是一个常量)(通过运算符*),那么您的设计不需要列{{1}在原始的,因此它的分解没有表item_payment - 它是乘法表的某个限制;它是乘法表的一定功能。前两个表。

至于我的猜测,以及相关的CK(候选键)和理由:规范化使用FD(功能依赖),你还没有提到它们,所以看起来你甚至没有基本的想法你在干嘛所以现在你的问题只是要求一些教科书的一些章节。这太宽泛了 - 读一些。这里的答案都没有正确解释或引用如何做到这一点 - 它们对于下一个案例并没有用处。这种情况没有道理。此外,他们都在猜测你的规格,但应该问你适当的信息。