【问题标题】:I keep messing up 1NF我一直在搞砸1NF
【发布时间】:2011-08-02 23:47:15
【问题描述】:

对我来说,到目前为止,我发现关于 1NF 最容易理解的描述是“主键是唯一标识每一行的列(或列组)。 ' 在 www.phlonx.com 上 我理解冗余意味着每个键的每行不应超过 1 个值。超过 1 个值将是“冗余的”。对吧?

我仍然设法搞砸了很多次 1 NF。 我为我的在线披萨店发布了一个问题http://foo.com pizzashop here

我对第二范式中的某些东西感到困惑,只是注意到我在 1 NF 中开始出错。 现在我在想我需要 1NF 中的 3 个键来唯一标识每一行。 在这种情况下,我发现 order_id、pizza_id 和 topping_id 会为我做这件事。所以这是3列。因为如果您想知道哪个特定的披萨是哪个,您需要知道它的 order_id 是什么类型的披萨 (pizza_id) 以及上面有什么配料。如果您知道这一点,则可以查找所有其他内容。 然而,从对上一个问题的回答来看,这似乎是错误的,因为 topping_id 转到了另一个我不理解的表。 这是列的列表:

Order_id
订单日期
客户 ID
客户名称
电话
促销
黑名单 Y 或 N
客户地址
邮政编码
城市
电子邮件
Pizza_id
Pizza_name
尺寸
Pizza_price
金额
Topping_id
Topping_name
Topping_prijs
可用
Delivery_id
Delivery_zone
Deliveryguy_id
送货员姓名
交货 Y 或 N

编辑:我将第一个连接键的 id 标记为粗体。它们只是一个未标准化的列列表。它们不是 1 张桌子或 3 张桌子或任何东西

【问题讨论】:

  • 您在一个表中拥有所有这些列吗?那肯定会违反 2NF
  • @Gabor Kulcsar 我的问题是:我这样做的方法是否正确?如果不是,为什么不呢? @mar_s:不,这不是第二范式,上面的表格也不是一张大桌子。这是一个关于第一范式及其主键的问题
  • 我还是不明白。为什么要将所有东西都挤到一张桌子上?这不是 1NF 的要求……这是完全错误的。
  • @Gabor:上面的列列表不是一个开始的表格。它只是一个列列表。
  • @Jack_Anyway:您还不能拥有 ToppingID 或 Pizza_id 或 Order_id:它们没有任何意义。这是您在 BCNF 时的实施。

标签: sql normalization


【解决方案1】:

relational databases 的优势在于将信息分成不同的表格。查看表格的useful way 首先将那些相对永久的概念识别为实体表(在您的情况下,可能是 Pizza、Customer、Topping、Deliveryguy)。然后您考虑它们之间的关系(在您的情况下, Order, Delivery )。关系表通过foreign keys 指向相关实体将实体表链接在一起:Order 具有指向 Customer、Pizza、Topping 的外键); Delivery 具有 Deliveryguy 和 Order 的外键。而且,是的,关系可以链接关系,而不仅仅是实体。

只有在这样的情况下,你才能实现规范化之类的东西。将一堆属性扔到一个单一的表中不会使您的数据库具有任何有意义的关系。

【讨论】:

    【解决方案2】:

    使用Object Role Modelling(例如使用 NORMA)获取有关设计的信息,按下按钮,它会输出 SQL。

    这比让你在 1NF、2NF 等之间来回更容易。ORM 设计保证在 5NF 中。

    一些注意事项:

    • 可以拥有复合键
    • 代理键可以在概念和逻辑设计之后添加:你已经在前面添加了它们,这很糟糕。添加它们是因为 RDBMS 性能,而不是在设计时添加
    • 你有没有阅读几个关于 1NF 的资料?
    • 从简单的英语和一些事实开始。这就是 ORM 对语言的作用。

    所以:

    1. 一位客户有许多比萨饼(零到 n)
    2. 披萨有很多配料(零到 n)
    3. 客户有地址
    4. 披萨有底
    5. ...

    【讨论】:

    • 是的,我已经阅读了一些关于 1NF 的资源,问题是我阅读的越多,我就越困惑,这就是我问这个问题的原因。我一直在与正常化作斗争太久了,这让我很沮丧。就像当我使用人类语言技术时,我得到的结果与我严格使用 codd 规则时不同。我对我的教练说你应该能够在不知道你的列名含义的情况下进行规范化感到困惑。其他人说要运用你的常识,选择你认为合乎逻辑的东西。
    • @Jack_Anyway:只有当您知道(或假设)模型中存在的所有函数依赖项(并且有算法告诉您如何要做到这一点)。那么这是可能的。但是,FD 要么是从数据中推断出来的,要么是从您正在设计的模型的含义(语义)中推导出来的,因此设计和规范化之间存在自然而深刻的重叠。
    • 酷我有点明白了。它不必是非此即彼的事情。当然。
    【解决方案3】:

    在 1NF,来自维基百科,引用日期:

    根据Date对1NF的定义, 一个表在 1NF 中当且仅当它是 “与某种关系同构”,其中 具体而言,意味着它满足 以下五个条件:

    • 行没有从上到下的顺序。
    • 列没有从左到右的顺序。
    • 没有重复的行。
    • 每个行列交叉点恰好包含一个 来自适用域的值(和 没有别的)。
    • 所有列都是常规的 [即行没有隐藏的组件,例如 行 ID、对象 ID 或隐藏 时间戳]。

      —Chris Date,“第一范式的真正含义”,第 127–8[4] 页

    前两个在任何现代 RDBMS 中都得到保证。

    现代 RDBMS 中可能存在重复行,但前提是您没有主键(或其他唯一约束)。

    第四个是最难的(取决于您的模型的语义) - 例如,您的字段 Customer_address 可能会破坏 1NF。可能是因为如果您与自己(以及系统的任何潜在用户)签订合同,您将始终将地址视为一个整体,并且不想分开街道名称、街道编号和/或楼层,您仍然可以声称1NF 没有被破坏。

    打破客户地址会更合适,但那里存在复杂性,您需要解决这些问题并且可能不会带来任何好处(前提是您永远不必查看地址行)。

    第五个被一些现代 RDBMs 破坏了,但真正重要的是你的模型或系统应该依赖于隐藏元素,这通常是正确的 - 即使你的 RDBMS 在内部使用 OID 进行某些操作,除非你开始使用它们用于非管理、非维护任务,您可以认为它不破坏 1NF。

    【讨论】:

    • 你是对的,但它并没有真正帮助 OP:我怀疑他们需要实际的帮助......
    • @gbn,这是一个假设! :) 仅基于您的答案被接受并投票的事实! :)
    • 不,基于 OP 的问题。不是每个人都了解关系甚至简单的集合论......
    • 确实,我已经了解了很多理论,但现在更多的理论对我没有帮助。
    【解决方案4】:

    我会为此使用更多表格,以消除客户、订单、浇头和披萨的重复:

    表:客户

       Customer_id
        Customer_name
        Customer_name
        Phone
        Promotion
        Blacklist Y or N
        Customer_address
        ZIP_code
        City
        E_mail
    

    表格:顺序

    Order_id
    Order_date
    Customer_id
    Delivery_zone
    Deliveryguy_id
    Deliveryguy_name
    Delivery Y or N
    

    表:Order_Details

    Order_ID (FK on Order)
    Pizza_ID (FK on Pizza)
    Amount
    

    餐桌:比萨饼

    Pizza_id
    Pizza_name
    Size
    Pizza_price
    

    表格:顶部

    Topping_id
    Topping_name
    Topping_prijs
    Availabitly
    

    表:Pizza_Topping

    Pizza_ID
    Topping_ID
    

    Pizza_topping 和 Order_details 是所谓的选择表(用于对两个表之间的 m:n 关系建模的“辅助”表)。

    现在假设我们只有一个披萨和一些配料,而我们的客户 Billy Smith 订购了 2 个 quattro stagione 披萨 - 我们的表格将包含以下内容:

    Pizza(Pizza_ID、Pizza_name、Pizza_price)

      1 Quattro stagioni 12€
    

    Topping(Topping_id, topping_name, topping_price)

      1 Mozzarrella 0,50€
      2 Prosciutto 0,70€
      3 Salami 0,50€
    

    Pizza_Topping(Pizza_ID, Topping_ID)

     1 1
     1 3
    

    (这里,quattro stagioni 比萨只包含马苏里拉奶酪和意大利腊肠)。

    Order(order_ID, Customer_name - 其余省略)

    1 Billy Smith
    

    Order_Details(order_id, Pizza_id, amount)

    1 1 2  
    

    我删除了交货 ID,因为对我来说,订单和交货之间没有区别 - 还是您支持部分交货?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-02
      • 1970-01-01
      • 1970-01-01
      • 2021-11-02
      • 1970-01-01
      相关资源
      最近更新 更多