LEFT OUTER JOIN 和 NOT EXISTS 查询

Posted

技术标签:

【中文标题】LEFT OUTER JOIN 和 NOT EXISTS 查询【英文标题】:LEFT OUTER JOIN and NOT EXISTS query 【发布时间】:2013-03-14 12:38:59 【问题描述】:

我很难使用复杂的连接,我需要连接两次相同的两个表,并确保每次只使用特定记录(最近的记录)完成连接。

SELECT c.collection_id      AS collections, 
       s.strat_id           AS StrategyId, 
       s.strat_version      AS StrategyVersion, 
       ssb.side_ordering    AS SSB_SO, 
       ssb2.side_ordering   AS SSB2_SO, 
       Invoice1.invoice_id  AS Inv1ID, 
       Invoice2.invoice_id  AS Inv2ID, 
       Invoice1.printeddate AS Inv1PrintedDate, 
       Invoice2.printeddate AS Inv2PrintedDate 
  FROM dbo.collections AS c 
       INNER JOIN dbo.strategies AS s 
               ON c.collection_id = s.collection_id 
       INNER JOIN dbo.side_strat_brkrgs AS ssb 
               ON s.collection_id = ssb.collection_id 
                  AND s.strat_id = ssb.strat_id 
                  AND s.strat_version = ssb.strat_version 
       INNER JOIN dbo.strat_sides AS ss 
               ON ss.strat_side_id = ssb.strat_side_id 
       LEFT OUTER JOIN dbo.side_strat_brkrgs AS ssb2 
                    ON ssb2.collection_id = ssb.collection_id 
                       AND ssb2.strat_id = ssb.strat_id 
                       AND ssb2.strat_version = ssb.strat_version 
                       AND ssb2.side_ordering <> ssb.side_ordering 
       INNER JOIN dbo.strat_sides AS ss2 
               ON ss2.strat_side_id = ssb2.strat_side_id 
       LEFT OUTER JOIN dbo.newinvoiceitem AS InvoiceItem1 
                    ON ssb.collection_id = InvoiceItem1.collection_id 
                       AND ssb.side_ordering = InvoiceItem1.side_ordering 
                       AND s.strat_id = InvoiceItem1.strat_id 
       LEFT OUTER JOIN dbo.newinvoice AS Invoice1 
                    ON Invoice1.invoice_id = InvoiceItem1.invoice_id 
       LEFT OUTER JOIN dbo.newinvoiceitem AS InvoiceItem2 
                    ON ssb2.collection_id = InvoiceItem2.collection_id 
                       AND ssb2.side_ordering = InvoiceItem2.side_ordering 
                       AND s.strat_id = InvoiceItem2.strat_id 
       LEFT OUTER JOIN dbo.newinvoice AS Invoice2 
                    ON Invoice2.invoice_id = InvoiceItem2.invoice_id 
 WHERE NOT EXISTS (SELECT 1 
                     FROM dbo.newinvoiceitem tempInvoiceItem1 
                          INNER JOIN dbo.newinvoice AS tempInvoice1 
                                  ON tempInvoice1.invoice_id = 
                                     tempInvoiceItem1.invoice_id 
                    WHERE tempInvoiceItem1.collection_id = ssb.collection_id 
                          AND ssb.side_ordering = tempInvoiceItem1.side_ordering 
                          AND s.strat_id = tempInvoiceItem1.strat_id 
                          AND s.strat_version = tempInvoiceItem1.strat_version 
                          AND tempInvoice1.printeddate > Invoice1.printeddate) 
       AND NOT EXISTS (SELECT 1 
                         FROM dbo.newinvoiceitem tempInvoiceItem2 
                              INNER JOIN dbo.newinvoice AS tempInvoice2 
                                      ON tempInvoice2.invoice_id = 
                                         tempInvoiceItem2.invoice_id 
                        WHERE 
               tempInvoiceItem2.collection_id = ssb2.collection_id 
               AND ssb2.side_ordering = tempInvoiceItem2.side_ordering 
               AND s.strat_id = tempInvoiceItem2.strat_id 
               AND s.strat_version = tempInvoiceItem2.strat_version 
               AND tempInvoice2.printeddate > Invoice2.printeddate) 
       AND c.collection_id = 16447 

我得到以下结果:

16447   1   3   1   0   3785    3183    2010-05-06 17:52:00 2010-05-06 17:52:00 
16447   1   3   1   0   3785    4033    2010-05-06 17:52:00 2010-05-10 16:32:00 
16447   1   3   1   0   4137    3183    2010-05-20 17:08:00 2010-05-06 17:52:00 
16447   1   3   1   0   4137    4033    2010-05-20 17:08:00 2010-05-10 16:32:00

虽然我实际上只期待最后一行。我哪里错了?

如您所见,我不能使用 MAX() 来检索最高记录,因为我需要通过 JOIN 查找另一个属性,并且我不得不使用 NOT EXIST

【问题讨论】:

如果这是针对大型数据集,为了优化和可扩展性,我会考虑绕过左连接并将其分解为更小更易于管理的块 :) 你能稍微处理一下缩进吗?现在不可读。 您的查询有点复杂,我无法理解。通常,当查找最近的记录时,会使用 MAX() 来选择最高的发票编号或最迟日期。 您的第一个查询无法解析...并使用this 格式化您的查询... @Edmondo1984 在逻辑上而不是编辑器包装它们的位置插入换行符 - 在 FROM 下缩进表和连接,在 SELECT 下缩进列,使连接的 ON 条件在视觉上与加入他们所属的行列。 【参考方案1】:

试试这个谓词

 WHERE EXISTS (SELECT 1 
               FROM dbo.newinvoiceitem tempInvoiceItem1 
                 INNER JOIN dbo.newinvoice AS tempInvoice1 
                   ON tempInvoice1.invoice_id = tempInvoiceItem1.invoice_id 
               WHERE tempInvoiceItem1.collection_id = ssb.collection_id 
                 AND ssb.side_ordering = tempInvoiceItem1.side_ordering 
                 AND s.strat_id = tempInvoiceItem1.strat_id 
               HAVING MAX(tempInvoice1.printeddate) = Invoice1.printeddate
                 OR Invoice1.printeddate IS NULL
               )                          
       AND EXISTS (SELECT 1 
                   FROM dbo.newinvoiceitem tempInvoiceItem2 
                     INNER JOIN dbo.newinvoice AS tempInvoice2 
                       ON tempInvoice2.invoice_id = tempInvoiceItem2.invoice_id 
                   WHERE tempInvoiceItem2.collection_id = ssb2.collection_id 
                     AND ssb2.side_ordering = tempInvoiceItem2.side_ordering 
                     AND s.strat_id = tempInvoiceItem2.strat_id 
                   HAVING MAX(tempInvoice2.printeddate) = Invoice2.printeddate
                     OR Invoice2.printeddate IS NULL
                   ) 
       AND c.collection_id = 16447 

 WHERE EXISTS (SELECT 1 
               FROM dbo.newinvoiceitem tempInvoiceItem1 
                 INNER JOIN dbo.newinvoice AS tempInvoice1 
                   ON tempInvoice1.invoice_id = tempInvoiceItem1.invoice_id 
               WHERE tempInvoiceItem1.collection_id = ssb.collection_id 
                 AND ssb.side_ordering = tempInvoiceItem1.side_ordering 
                 AND s.strat_id = tempInvoiceItem1.strat_id 
               HAVING MAX(tempInvoice1.printeddate) = Invoice1.printeddate                     
               )                          
       AND EXISTS (SELECT 1 
                   FROM dbo.newinvoiceitem tempInvoiceItem2 
                     INNER JOIN dbo.newinvoice AS tempInvoice2 
                       ON tempInvoice2.invoice_id = tempInvoiceItem2.invoice_id 
                   WHERE tempInvoiceItem2.collection_id = ssb2.collection_id 
                     AND ssb2.side_ordering = tempInvoiceItem2.side_ordering 
                     AND s.strat_id = tempInvoiceItem2.strat_id 
                   HAVING MAX(tempInvoice2.printeddate) = Invoice2.printeddate
                   ) 
       AND c.collection_id = 16447 OR Invoice1.printeddate IS NULL
         OR Invoice2.printeddate IS NULL

【讨论】:

这会为我返回一个空集:( 39 分钟前编辑的最后一个版本有效。你能解释一下原因吗? 我认为 EXISTS() 运算符 s.strat_version = tempInvoiceItem1.strat_version 中的条件过多,因为对于行数据比较,我们需要相同的数据集。 回到主题,这会将左外连接变成内连接...我也想要NULL 没问题;) 只需添加条件 Invoice1.printeddate IS NULL/Invoice2.printeddate IS NULL。答案已更新

以上是关于LEFT OUTER JOIN 和 NOT EXISTS 查询的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 数据库中 left outer join 和 left join 啥区别?

SQL Server 中的 LEFT JOIN 与 LEFT OUTER JOIN

KTable vs GlobalKTable 和 left Join() vs outer Join() 有啥区别?

Inner Join, Left Outer Join和Association的区别

CROSS JOIN和INNER JOIN,LEFT JOIN,RIGHT JOIN,OUTER JOIN之间的区别[重复]

left join ,right join ,inner join,outer join,union all,union有啥区别?怎么用?