2

所以,我有以下两个查询。在第一个查询中,rcv_transaction表首先在 select 子句中按 TRANSACTION_TYPE 过滤,然后连接到其他表,而在第二个查询中,表首先连接,然后在 WHERE 子句中过滤。结果完全不同。第一个查询产生的结果几乎是第二个查询的两倍。对我来说,他们应该执行相同的任务。我在这里想念什么?有什么不同?

第一个。询问

SELECT pl.*
  FROM po_headers_all ph,
       po_lines_all pl,
       (SELECT *
          FROM rcv_transactions r
         WHERE r.TRANSACTION_TYPE = 'DELIVER') rt
 WHERE     ph.PO_HEADER_ID = pl.PO_HEADER_ID
       AND rt.po_header_id(+) = pl.po_header_id
       AND rt.po_line_id(+) = pl.po_line_id

第二次查询

SELECT pl.*
    FROM   po_headers_all ph, 
           po_lines_all pl, 
           rcv_transactions rt
     WHERE     ph.PO_HEADER_ID = pl.PO_HEADER_ID
           AND rt.po_header_id(+) = pl.po_header_id
           AND rt.po_line_id(+) = pl.po_line_id
           AND rt.transaction_type = 'DELIVER'
4

2 回答 2

2

使用 ANSI 92 连接语法,您的查询将被重写为:

SELECT  pl.*
FROM    po_headers_all ph, 
        INNER JOIN po_lines_all pl, 
            ON ph.PO_HEADER_ID = pl.PO_HEADER_ID
        LEFT JOIN rcv_transactions rt
            ON rt.po_header_id = pl.po_header_id
            AND rt.po_line_id = pl.po_line_id
            AND rt.transaction_type = 'DELIVER';

SELECT  pl.*
FROM    po_headers_all ph, 
        INNER JOIN po_lines_all pl, 
            ON ph.PO_HEADER_ID = pl.PO_HEADER_ID
        LEFT JOIN rcv_transactions rt
            ON rt.po_header_id = pl.po_header_id
            AND rt.po_line_id = pl.po_line_id
WHERE   rt.transaction_type = 'DELIVER';

由于rcv_transactions当此表中没有相应行时,您的联接是左联接,因此查询将返回 NULL。但是,您的第二个查询在WHERE子句中规定rt.transaction_type = 'DELIVER',因此任何不匹配的行都rcv_transactions将被排除,因为NULL不等于DELIVER。这有效地将您的 LEFT JOIN 转换为 INNER JOIN。在第一个查询中,尽管此谓词是您的一部分,但JOIN您不会影响整体结果,只会影响连接的记录。

于 2013-09-20T13:36:17.853 回答
0

如果您检查执行计划,您会看到第二个查询没有执行外连接,正如 GarethD 已经解释的那样。将连接运算符添加到最后一行以将其作为连接条件包含在内:

AND rt.transaction_type(+) = 'DELIVER'
于 2013-09-20T14:23:44.080 回答