所以我知道某些事情在 SQL 中是如何工作的,但我不知道为什么,而且我无法在网上找到一个很好的外行描述。作为参考,我使用的是 Oracle 11g 和 TOAD。
问题 1 - 符合条件的外部联接
我知道,如果您在外部联接表上放置条件,则无论您的语法如何,您都会将查询转换为内部联接。所以这个查询作为一个内部连接:
SELECT a.field1, b.field1
FROM tableA a
LEFT JOIN tableB b on a.key = b.key
WHERE b.field2 = 'someCriteria'
解决此问题的方法是在第二个表的条件中包含“OR IS NULL”。我知道这是真的,但我一直无法理解为什么会这样。有人可以解释为什么外部表上的标准将外部联接变成内部联接吗?
问题 2 - 将标准添加到不同的子句更改结果
所以以上是真的,我一直在努力解决我的标准顺序如何改变以下两个查询的结果。我有两个表 - tableA 和 tableB - 并且需要对 tableA 的子集与 tableB 的子集进行左连接比较。
SQL1
SELECT DISTINCT a.field1, b.field2
FROM tableA a
LEFT JOIN tableB b
on a.key = b.key
AND (b.field2 = 'somecriteria' or b.field2 IS NULL)
WHERE a.field1 = 'othercriteria'
结果:SQL1 给了我正确的左连接结果。
SQL2
SELECT DISTINCT a.field1, b.field2
FROM tableA a
LEFT JOIN tableB b
on a.key = b.key
WHERE a.field1 = 'othercriteria'
AND (b.field2 = 'somecriteria' or b.field2 IS NULL)
结果:SQL2 仅拉回两个子集的内部连接结果(不包括 tableA 中 tableB 不匹配的那些行)。
了解结果
其原因与 join 和 where 运行的顺序有关。我可以理解这种不断变化的性能,但我不理解为什么它会改变结果,因为语法几乎相同。为了解决这个问题,我运行了两个查询的执行计划并得到了以下结果(来自 TOAD):
执行计划:
SQL 1:
- 5) Select 语句(行由 Select 语句返回)
- 4) 唯一排序(对第 3 步中的行进行排序以消除重复行)
- 3) Hash Join Right Outer (第 1、2 步的结果集被加入 (hash)
- 1)表访问Full TABLE tableB(表tableB中的每一行都被读取)
- 2)Table Access Full TABLE tableA(读取tableA中的每一行)
- 3) Hash Join Right Outer (第 1、2 步的结果集被加入 (hash)
SQL 2:
- 11) Select 语句(行由 Select 语句返回)
- 10) 唯一排序(对第 9 步中的行进行排序以消除重复行)
- 9) 返回步骤 4、8 中的所有不同行
- 4)过滤(对于第3步返回的行,根据过滤条件过滤掉行)
- 3) Hash Join Right Outer (第 1、2 步的结果集被加入 (hash)
- 1)表访问Full TABLE tableB(表tableB中的每一行都被读取
- 2)Table Access Full TABLE tableA(读取tableA中的每一行)
- 8)过滤(对于第7步返回的行,根据过滤条件过滤掉行)
- 7) Hash Join Right Outer (第 5、6 步的结果集被加入 (hash)
- 5)Table Access Full TABLE tableB(读取tableB中的每一行)
- 6)Table Access Full TABLE tableA(读取tableA中的每一行)
- 4)过滤(对于第3步返回的行,根据过滤条件过滤掉行)
所以我毫不怀疑上述执行计划完美地解释了为什么 SQL 2 给我的结果与 SQL 1 不同,但我很难阅读这些计划。有人可以帮我翻译这些执行计划并解释为什么 SQL2 被视为 Inner Join,因为 tableA 标准列在 WHERE 子句而不是 JOIN 中?
提前致谢!!