Oracle (+) 外连接和常量值
Oracle (+) outer join and constant values
我 运行 遇到了一个问题,我不知道如何正确配置连接。我正在使用报告软件,该软件在我们的 Oracle 数据库的 WHERE 子句中使用 (+) 指示符。我有两个表:
支票和交易。一张支票可以有多个交易,但一个交易不一定有对应的支票。
两个表都有标识当前记录的指示符,称为 CURRENT,它是 'Y' 或 'N'。
加入选项 1:
Select *
FROM TXN,CHK
WHERE
TXN.CHK_ID = CHK.CHK_ID(+)
and TXN.CURRENT = 'Y'
and CHK.CURRENT = 'Y'
加入选项 2:
Select *
FROM TXN,CHK
WHERE
TXN.CHK_ID = CHK.CHK_ID(+)
and TXN.CURRENT = 'Y'
and CHK.CURRENT(+) = 'Y'
这些联接产生不同的结果,我似乎无法弄清楚额外的外部联接指示器在应用于 CHK.CURRENT 字段时会产生什么影响。带有额外指示符的查询会产生更大的结果集。有人可以帮忙解释一下这是怎么回事吗?
我将使用等效的 "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
table 表达式后,即在 的结果上应用常量谓词LEFT JOIN
.
在选项 2 中,您的常量谓词之一是 LEFT JOIN
表达式的一部分。
LEFT JOIN
是如何工作的?
LEFT JOIN
的想法是它将 return 来自 JOIN
表达式的 LEFT 侧的所有行,无论是否给定连接谓词,另一侧有一个匹配行。因此,在选项 2 中,无论您是否在 CHK
中找到一行 TXN
中的一行 CURRENT = 'Y'
,TXN
中的行仍然是 returned .这就是您在选项 2 中获得更多行的原因。
另外,这个例子应该解释为什么你应该更喜欢 "ANSI JOIN" 语法。从维护/可读性的角度来看,您的查询在做什么更加清楚。
。(+)
运算符告诉 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
中找到匹配的行或者是否执行左外连接。
加入选项 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'
加入选项 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
上匹配并且查询实际上等同于:
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 )
我 运行 遇到了一个问题,我不知道如何正确配置连接。我正在使用报告软件,该软件在我们的 Oracle 数据库的 WHERE 子句中使用 (+) 指示符。我有两个表:
支票和交易。一张支票可以有多个交易,但一个交易不一定有对应的支票。
两个表都有标识当前记录的指示符,称为 CURRENT,它是 'Y' 或 'N'。
加入选项 1:
Select *
FROM TXN,CHK
WHERE
TXN.CHK_ID = CHK.CHK_ID(+)
and TXN.CURRENT = 'Y'
and CHK.CURRENT = 'Y'
加入选项 2:
Select *
FROM TXN,CHK
WHERE
TXN.CHK_ID = CHK.CHK_ID(+)
and TXN.CURRENT = 'Y'
and CHK.CURRENT(+) = 'Y'
这些联接产生不同的结果,我似乎无法弄清楚额外的外部联接指示器在应用于 CHK.CURRENT 字段时会产生什么影响。带有额外指示符的查询会产生更大的结果集。有人可以帮忙解释一下这是怎么回事吗?
我将使用等效的 "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
table 表达式后,即在 的结果上应用常量谓词LEFT JOIN
.
在选项 2 中,您的常量谓词之一是 LEFT JOIN
表达式的一部分。
LEFT JOIN
是如何工作的?
LEFT JOIN
的想法是它将 return 来自 JOIN
表达式的 LEFT 侧的所有行,无论是否给定连接谓词,另一侧有一个匹配行。因此,在选项 2 中,无论您是否在 CHK
中找到一行 TXN
中的一行 CURRENT = 'Y'
,TXN
中的行仍然是 returned .这就是您在选项 2 中获得更多行的原因。
另外,这个例子应该解释为什么你应该更喜欢 "ANSI JOIN" 语法。从维护/可读性的角度来看,您的查询在做什么更加清楚。
。(+)
运算符告诉 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
中找到匹配的行或者是否执行左外连接。
加入选项 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'
加入选项 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
上匹配并且查询实际上等同于:
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 )