Oracle(+)外连接和常量值

时间:2015-12-16 20:50:40

标签: sql oracle left-join

我遇到了一个问题,我无法弄清楚如何正确配置连接。我正在使用报告软件,该软件利用WHERE子句中的(+)指标为我们的Oracle数据库。我有两张桌子:

检查和交易。支票可以有多个交易,但交易不一定有相应的支票。

两个表都有指示器,用于标识名为CURRENT的当前记录,即“Y”或“N”。

加入选项1:

json_encode()

加入选项2:

Select *
FROM TXN,CHK
WHERE
TXN.CHK_ID = CHK.CHK_ID(+)
and TXN.CURRENT = 'Y'
and CHK.CURRENT = 'Y'

这些连接产生不同的结果,我似乎无法弄清楚当应用于CHK.CURRENT字段时额外的外连接指示符有什么影响。带有额外指标的查询会产生更大的结果集。有人可以帮忙解释一下这里发生了什么吗?

4 个答案:

答案 0 :(得分:6)

我将通过使用等效的“ANSI JOIN”语法来解释这一点:

选项1

SELECT *
FROM TXN
LEFT JOIN CHK 
  ON TXN.CHK_ID = CHK.CHK_ID
WHERE TXN.CURRENT = 'Y'
AND CHK.CURRENT = 'Y'

选项2

SELECT *
FROM TXN
LEFT JOIN CHK 
  ON TXN.CHK_ID = CHK.CHK_ID 
  AND CHK.CURRENT = 'Y'
WHERE TXN.CURRENT = 'Y'

正如您所看到的,在选项1中,在指定LEFT JOIN表表达式之后,即LEFT JOIN的结果,应用

在选项2中,您的一个常量谓词是LEFT JOIN表达式的一部分。

LEFT JOIN如何运作?

LEFT JOIN的想法是它将返回JOIN表达式的 LEFT 侧的所有行,无论另一侧是否有匹配的行,给定连接谓词。因此,在选项2中,无论您在CHK中找到CURRENT = 'Y'行还是TXN中的行,都会返回TXN中的行。这就是您在选项2中获得更多行的原因。

此外,此示例应解释为什么您应该更喜欢“ANSI JOIN”语法。从维护/可读性的角度来看,您的查询正在做的事情要清楚得多。

答案 1 :(得分:2)

(+)运算符告诉Oracle谓词是外连接的一部分,而不是可以在连接后应用的过滤谓词。使用SQL 99外连接语法,第一个查询等同于

SELECT *
  FROM txn
       left outer join chk 
         on( txn.chk_id = chk.chk_id )
 WHERE txn.current = 'Y'
   AND chk.current = 'Y'

而第二个相当于

SELECT *
  FROM txn
       left outer join chk 
         on( txn.chk_id  = chk.chk_id AND
             chk.current = 'Y')
 WHERE txn.current = 'Y'

逻辑上,在第一种情况下,您执行外部联接,但随后将chk.current NULL chk.current = 'Y'的所有行过滤掉。在第二种情况下,chk条件不会过滤掉任何行,它只控制是否在class table: def __init__(self): self.h = 0 self.g = 0 中找到匹配的行,或者是否执行了左外连接。

答案 2 :(得分:0)

加入选项1将仅考虑CHK.CURRENT =' Y'的那些行。因此,如果事务没有检查,CHK.CURRENT将为NULL,并且该行不在结果集中。

加入选项2将考虑CHK.CURRENT(如果有检查)是' Y'的那些行。如果事务没有检查,则不会应用此测试,并且该行将位于结果集中。

您可以看到与此比较的区别:

Select *
FROM TXN,CHK
WHERE
TXN.CHK_ID = CHK.CHK_ID(+)
and TXN.CURRENT = 'Y'
and CHK.CURRENT(+) = 'Y'
MINUS
Select *
FROM TXN,CHK
WHERE
TXN.CHK_ID = CHK.CHK_ID(+)
and TXN.CURRENT = 'Y'
and CHK.CURRENT = 'Y'

答案 3 :(得分:0)

加入选项1相当于:

SELECT *
FROM   TXN
       LEFT OUTER JOIN CHK
       ON ( TXN.CHK_ID = CHK.CHK_ID )
WHERE  TXN.CURRENT = 'Y'
AND    CHK.CURRENT = 'Y'

但是,由于结果集中的任何行都将具有CHK.CURRENT = 'Y'(非空值),因此这些行必须在CHK_ID上匹配,并且查询实际上相当于:< / p>

SELECT *
FROM   TXN
       INNER JOIN CHK
       ON ( TXN.CHK_ID = CHK.CHK_ID )
WHERE  TXN.CURRENT = 'Y'
AND    CHK.CURRENT = 'Y'

加入选项2相当于:

SELECT *
FROM   TXN
       LEFT OUTER JOIN CHK
       ON (    TXN.CHK_ID  = CHK.CHK_ID
           AND CHK.CURRENT = 'Y' )
WHERE  TXN.CURRENT = 'Y'

您可以使用以下方式使加入选项1等同于选项2

SELECT *
FROM   TXN
       LEFT OUTER JOIN CHK
       ON ( TXN.CHK_ID = CHK.CHK_ID )
WHERE  TXN.CURRENT = 'Y'
AND    ( CHK.CURRENT = 'Y' OR CHK.CHK_ID IS NULL )