【问题标题】:SQL Full Outer Join duplicate IssueSQL完全外连接重复问题
【发布时间】:2018-07-12 07:36:56
【问题描述】:

我已经对此进行了相当多的搜索,但我只是看不出哪里出错了。我希望有人能帮我弄清楚。我有两张表,一张用于零件编号的所有销售订单 (SO),一张用于零件编号的所有采购订单 (PO)。我想将结果合并在一起。大多数情况下,每个零件的采购订单和销售订单数量不会相同。在此示例中,我有 2 个销售订单和 1 个采购订单。

Table 1 (SO)
Company     Part     SalesOrder
ABC         123       5530
ABC         123       6854
ABC         456       7772
ABC         456       6868

Table 2 (PO)
Company     Part     PurchaseOrder
ABC         123       9889
ABC         456       9308
ABC         456       9655
ABC         456       9774

我希望看到:

Company     Part     SalesOrder     PurchaseOrder
ABC         123       5530            9889
ABC         123       6854            NULL
ABC         456       7772            9308
ABC         456       6868            9655
ABC         456       NULL            9774

但我看到了:

Company     Part     SalesOrder     PurchaseOrder
ABC         123       5530            9889
ABC         123       6854            9889
ABC         456       7772            9308
ABC         456       7772            9655
ABC         456       7772            9774
ABC         456       6868            9308
ABC         456       6868            9655
ABC         456       6868            9774

这是我的查询:

 select coalesce(SO.Company, PO.Company) as Company,
 coalesce(SO.Part, PO.Part) as Part, 
 SO.SalesOrder, PO.PurchaseOrder 
 from  SO full outer join PO
 on SO.Company=PO.Company and SO.Part=PO.Part

也许我不需要完全外部连接来实现这一点?作为参考,我查看了类似的帖子 SQL Full Outer Join 我认为我想要的结果与帖子中的结果相似,我认为我的查询看起来像选择的解决方案,但显然我在某个地方失败了。我非常感谢任何帮助。

----更新---- 我想我造成了一些混乱,为此,我深表歉意。只是为了澄清一下,PO 和 SO 之间没有任何关系,它们只是针对同一部分。不会创建特定的 PO 来完成特定的 SO。有些零件可能只有 SO(例如,制造零件),有些可能只有 PO(制造物品的组件)。有些部分碰巧有相同数量的 SO 和 PO,但大多数时候,可能不止一个。例如,如果我想查看某个部件的历史活动,可能有 4 个销售订单和 1 个采购订单。如果我要进行联合,我基本上将“活动”(SO's/Po's)集中到一列中,那么对于那部分,查询将返回 5 行活动(4 个 SO's/1 个 PO)。但是,不是有 1 列和 5 行,而是我可以做到有 2 列(一列用于 SO,一列用于 PO)并有 4 行吗? SO 列中的所有行都不会为空,对于 PO,4 为空,而 1 则不会。让第一行包含不为空的 PO 行只是一种视觉偏好,但绝不是第一行的 SO 和 PO 实际上相关,除了它们恰好位于同一行。

举一个完全不同的例子:

假设我有一个客户表和一个供应商表,它们都有“名称”和“州”的字段名称,我想列出我在加利福尼亚的所有客户或供应商。我可以做一个工会吗?

select c.name, 'Cust' as Type, c.state
from customer c 
where c.state='CA'
union
select v.name, 'Vend', v.state
from vendor v
where v.state='CA'

我会得到类似的东西:

Name          Type     State
BB Shrimp     Cust     CA
Vista Inc     Cust     CA
Mary's Lamb   Cust     CA
Cali Coffee   Cust     CA
Cool Guys     Cust     CA
Tap Corp      Vendor   CA
Blue Supply   Vendor   CA
Sun Shore     Vendor   CA

但我想看到这个:

Vendor       Customer     State
Tap Corp     BB Shrimp     CA
Blue Supply  Vista Inc     CA
Sun Shore    Mary's Lamb   CA
NULL         Cali Coffee   CA
NULL         Cool Guys     CA
NULL         Tap Corp      CA

我可以看到你会问,我为什么想看到那个,但如果我有这样的数据,我可以把它扔到 SSRS 中,让它看起来像

 State   Vendors      Customers  
 CA      Tap Corp     BB Shrimp 
         Blue Supply  Vista Inc                 
         Sun Shore    Mary's Lamb                           
                      Cali Coffee   
                      Cool Guys                

现在将 State 切换为 Part,将 Vendor 切换为 PO,将 Customer 切换为 SO,这就是我想要实现的目标。供应商和客户除了来自同一个州外没有任何关系,有些州的供应商可能比客户多,他们可能有相同的,但不相关。 PO 和 SO 的目标相同。

【问题讨论】:

  • 这就是连接的工作方式。左起 2 行,右起 3 行 =6。你到底想要什么?事实上,如果一行没有出现在其中一个表中,你只会得到空值。
  • 我不明白这个结果的原因是什么:ABC 123 6854 NULL 你只是根据行号吗?
  • 嗨。 “将结果合并在一起”没有任何意义。说出你的意思。为什么这张桌子是你“希望看到的”?您使用的是什么定义?为什么不参考一个?为什么要给出一个不包含的链接?另外,您没有在输入方面说想要的输出(尽管您举了一个例子),那么不管完全连接做什么,我们怎么知道您想要什么?请将您的帖子编辑成最好的当前演示文稿。不要附加新文本。添加更多内容并不会使不清楚的内容更清晰。
  • PS 请不要解释为什么你想要你想要的。 (更不用说漫无边际的了)。告诉我们你想要什么。

标签: sql sql-server tsql join outer-join


【解决方案1】:

您似乎想根据 PO 和 SO 的顺序对它们进行配对,但 FULL OUTER JOIN 只是将它们以所有可能的组合配对。如果你想捕获订单,你需要先做一个ROW_NUMBER():

SELECT COALESCE(SO2.company, PO2.company) AS Company,
       COALESCE(SO2.part, PO2.part)       AS Part,
       so.salesorder,
       po.purchaseorder
FROM   (SELECT *,
               Row_number()
                 OVER (
                   partition BY so.part, so.company
                   ORDER BY so.salesorder) AS SO_Sequence
        FROM   so) AS SO2
       FULL OUTER JOIN (SELECT *,
                               Row_number()
                                 OVER (
                                   partition BY po.part, po.company
                                   ORDER BY po.purchaseorder) AS PO_Sequence
                        FROM   po) AS PO2
                    ON SO2.company = PO2.company
                       AND SO2.part = PO2.part
                       AND SO2.so_sequence = PO2.po_sequence 

【讨论】:

  • 我不想在技术上配对 SO 和 PO。如果您可以对联合查询进行映像,则只需使用“123”部分。作为一个联合,SO/PO # 是一个共享列,它将返回 3 行,对吗?现在想象一下,但不是返回 1 列 3 行,我想返回 2 列(SO/PO)和 2 行(2 行,因为 SO 或 PO 的最高计数为 2。假设一个部分有 10 PO 和 3 个 SO,我想要两列(一列用于 SO,一列用于 PO)和 10 行,没有一个 PO 会为空,但 10 行中有 7 行 SO 对我来说,这并不重要行为空。
  • @jenhil34 想象一下测试解决方案
  • 谢谢,我不知道 COALESCE
【解决方案2】:

这是 OUTER JOIN 的本质。您的 LEFT 表就是您的 SO。对于 SO 中的每一行,您都有一个零件号和订单号,并将在您的结果集中收到一行。一旦评估了所有 LEFT 行,sql 将评估 RIGHT 表中的行,因此您会在两个表集中的每一行的结果集中获得一行。

你看到的原因

Company     Part     SalesOrder     PurchaseOrder
ABC         123       5530            9889
ABC         123       6854            9889

代替

Company     Part     SalesOrder     PurchaseOrder
ABC         123       5530            9889
ABC         123       6854            NULL

是因为它在零件号和公司上仍然匹配。

OUTER JOIN 是获得您正在寻找的结果的正确方法,但您当前的关系模型还不够明确,无法正确实现目标。

如果你应该有一个 1::1 的关系,你应该在 SO 表中有一个 PO id,或者在 PO 表中有一个 SO id。

@Greg Viers 展示了一种将贵公司/零件组合的 PO 表中第一次出现的 PO id 分配给 SO 表中的第一次出现的方法。然而,几乎在每一个商业案例中,都可以按照收到的顺序填写订单。你的订单也没有数量吗?您当前的设置在您的数据关系中留下了很多空白。

这在数据方面也更难维护;例如,如果采购订单被取消会怎样?

【讨论】:

    【解决方案3】:

    我只关注您预期的 Result 中的第 2 行和第 5 行。我认为 SalesOrder 的第 5 行预期 NULL 是错误的,我认为应该是 6884 。 这是支持我的主张的逻辑。我不知道你是如何得到结果的,但我尝试了相同的查询,我得到了你的预期结果

    CREATE TABLE #SO ( 
    Company NVARCHAR(16),
    PART NVARCHAR(16),
    SalesOrder NVARCHAR(16) ) 
    
    INSERT INTO #SO VALUES('ABC','123','6854')
    INSERT INTO #SO VALUES ('ABC','456','6868')
    
    
    
    CREATE TABLE #PO ( 
    Company NVARCHAR(16),
    PART NVARCHAR(16),
    PurchaseOrder NVARCHAR(16) ) 
    
    INSERT INTO #PO VALUES('ABC','456','9308')
    INSERT INTO #PO VALUES ('ABC','456','9774')
    
    select * from #SO 
    SELECT * FROM #PO
    
    
    SELECt coalesce(PO.COMPANY, SO.COMPANY) as Company 
         , coalesce(SO.PART, PO.PART) as Part 
         , SO.SalesOrder,po.PurchaseOrder 
          FROM #SO AS SO 
                    FULL OUTER JOIN #PO AS PO
                     ON  PO.PART = SO.PART AND 
              PO.Company = SO.Company
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-17
      • 2017-06-10
      • 2012-01-06
      • 1970-01-01
      • 2011-12-26
      • 1970-01-01
      • 2017-07-05
      相关资源
      最近更新 更多