SQL - 空外键或联结表?
Posted
技术标签:
【中文标题】SQL - 空外键或联结表?【英文标题】:SQL - Null foreign key or junction table? 【发布时间】:2012-05-10 18:36:05 【问题描述】:我的问题涉及 0 到多个关系。例如,如果您有一个客户表和一个订单表,一个客户可以有一个或多个订单,而一个订单可以有零个或一个客户。它可以为零的原因是因为订单是从遗留订单系统导入的,其中没有保留客户详细信息。
我相信有两种选择:
-
对于没有客户的订单,将 CustomerID(Orders 表中的外键)设置为 null。
在客户和订单之间创建一个包含 CustomerID 和 OrderID 的联结表。但是,我认为联结表专门用于多对多关系
哪个是最好的选择?
编辑:
我发现了以下帖子并同意 Molf 的回答,这是我原来问题中的选项 2:Any example of a necessary nullable foreign key?。
【问题讨论】:
除非我理解错了,否则订单表自然是联结表。客户 订单 order_items,除非您的订单只针对单个项目。一次。 @MarkB,是的,每个订单都有一个商品。 你能把引用帖子的链接放上去吗? 谢谢,转盘。我已经添加了链接。 +1。 【参考方案1】:我不会创建联结表,除非您最初打算将顺序键限制为唯一和/或预见到关系变为多对多。
具有普通单个 FK 的更简单的两表选项中的问题是您是否希望在订单行中允许 NULL 客户 FK。当然可以不允许这样做(出于明显的良好参考完整性原因),并有一个“未知客户”客户,用于所有具有未知客户的旧订单。以一种非常好的方式,这将 NULL(可能被误解)替换为明确的内容(对“未知客户”的引用,一旦创建或识别出真正的客户,就可以随时修复)。
我会强烈考虑这一点,因为人们希望遗留数据在您未来的数据中所占的比例越来越小,并且您希望确保您的数据中的 RI 对于典型案例(所有案例都在未来必须在创建订单期间识别客户),同时仍然适应遗留案例(随着时间的推移,这些案例在您的数据世界中的重要性会逐渐降低)
【讨论】:
【参考方案2】:您在这里有一个概念上令人困惑的冗余,尽管您可能对此有要求。如果您从头开始执行此操作,您可以简单地让 Orders 具有 Customer.CustomerID 的 NULLable FK。这将满足有 1 个客户 - 许多订单和 1/0 个客户的订单。您也可以通过使用联结表来做到这一点,因为这在技术上是多对多关系。
最好的选择取决于您查询数据的方式。例如,对 Orders 表进行分析型查询可能更方便
寻找没有客户的订单
SELECT SUM(CASE WHEN customer iS NULL THEN 1 ELSE 0 END) FROM Orders
对
SELECT SUM(CASE WHEN j.oid iS NULL THEN 1 ELSE 0 END) FROM
Orders o LEFT OUTER JOIN Junction j
WHERE o.o_id = j.o_id
您可以提出其他示例也可以进行更简洁、更高效的查询。
【讨论】:
谢谢。我不明白你的第一段 - 这不是我在问题中所说的摘要吗?你的第二段说选项二更好。 是的,这或多或少是一个摘要,因为我很困惑是否存在您正在尝试调整的当前架构。无论如何,在不知道如何访问数据的情况下很难判断哪个是最好的,但老实说,我认为这不会太重要。 我想我想说的是,这些在概念上是一样的,NULL 的情况是一种退化的多对多 你认为选项 2 的设计更好吗? 我认为您的第二个查询应该引用 customerid 而不是 customer。我想你想说没关系,我选择哪个选项?以上是关于SQL - 空外键或联结表?的主要内容,如果未能解决你的问题,请参考以下文章
使用TableHasPrimaryKey或TableHasForeignKey来知道表是否有主键或外键