Oracle 带过滤器的全外连接 (ANSI) 未按预期工作

标签 oracle filter oracle11g outer-join ansi-sql

我遇到了一个问题,即带有过滤器的 Oracle ANSI 完全外连接没有返回我期望的结果。我创建了一个简单的示例来解释我正在做什么和看到什么......

Table 1 - MUPPET

ID  NAME    
1   Kermit the Frog    
2   Fozzie Bear    
3   Mrs. Piggy    
4   Beaker    
5   Animal    
6   Swedish Chef

Table 2 - PHONE

ID  MUPPET_ID      PHONE    VALID
1   1      1111111111      Y
2   1      2222222222      N
3   2      3333333333      Y
4   4      4444444444      Y
5   5      5555555555      Y
6   6      6666666666      Y
7   6      7777777777      N
8   8      8888888888      Y

我想从这些表中选择所有布偶和所有有效的电话号码。我想要所有的布偶,无论它们是否有电话号码,并且我想选择所有有效的电话号码,无论它们是否与布偶相关联。这是我期望工作的查询...

SELECT   m.id muppet_id,
         m.name,
         p.id phone_id,
         p.phone,
         p.valid
  FROM      muppet m
         FULL OUTER JOIN
            phone p
         ON (M.ID = P.MUPPET_ID AND P.VALID = 'Y')

但这里的结果包含无效电话,即使我在外部连接过滤器中未指定无效电话

MUPPET_ID   NAME    PHONE_ID    PHONE   VALID

1   Kermit the Frog    1    1111111111  Y
                       2    2222222222  N
2   Fozzie Bear        3    3333333333  Y
4   Beaker             4    4444444444  Y
5   Animal             5    5555555555  Y
6   Swedish Chef       6    6666666666  Y
                       7    7777777777  N
                       8    8888888888  Y
3   Mrs. Piggy          

我终于能够使用完整外部连接左侧的子选择来获得我正在寻找的结果

SELECT   m.id muppet_id,
         m.name,
         p.id phone_id,
         p.phone,
         p.valid
  FROM      muppet m
         FULL OUTER JOIN
            (SELECT   id,
                      phone,
                      valid,
                      muppet_id
               FROM   phone
              WHERE   valid = 'Y') p
         ON (M.ID = P.MUPPET_ID) 

...以及结果...

MUPPET_ID   NAME      PHONE_ID  PHONE   VALID

1   Kermit the Frog           1 1111111111  Y
2   Fozzie Bear               3 3333333333  Y
4   Beaker                    4 4444444444  Y
5   Animal                    5 5555555555  Y
6   Swedish Chef              6 6666666666  Y
                              8 8888888888  Y
3   Mrs. Piggy

但我不明白为什么我必须这样查询。有人可以帮我解释为什么我使用过滤器的初始外部连接查询不能按预期工作吗?

编辑:

更有趣的是。当我运行此查询时,我按预期获得 6 条记录

select valid from (
SELECT   m.id muppet_id,
         m.name,
         p.id phone_id,
         p.phone,
         p.valid
  FROM      muppet m
         FULL OUTER JOIN
            phone p
         ON (M.ID = P.MUPPET_ID AND P.VALID = 'Y')
) where valid = 'Y'

但是当我运行这个时,我没有返回任何记录

select valid from (
SELECT   m.id muppet_id,
         m.name,
         p.id phone_id,
         p.phone,
         p.valid
  FROM      muppet m
         FULL OUTER JOIN
            phone p
         ON (M.ID = P.MUPPET_ID AND P.VALID = 'Y')
) where valid <> 'Y'

也许这是 Oracle 优化器或驱动程序的问题?

最佳答案

正如其他人在评论中所解释的那样,这是因为您放置过滤器逻辑的位置。因此,您的原始查询将返回所有布偶和所有电话号码,并在 ID 匹配且有效 =“Y”时将它们显示为已加入。因此,这就是为什么您会看到所有电话号码,但仅匹配有效的电话号码。

您可以采用您已经想出的方法,或者将“有效”逻辑移至 WHERE 子句中:

SELECT   m.id muppet_id,
         m.name,
         p.id phone_id,
         p.phone,
         p.valid
FROM      muppet m
         FULL OUTER JOIN
            phone p
         ON (M.ID = P.MUPPET_ID)
WHERE
         P.VALID = 'Y' or P.MUPPET_ID is null;

现在,where 子句将丢弃 VALID <> 'Y' 或电话表不匹配的行。如果您仅将 where 子句设置为“P.VALID = 'Y'”,那么您将有效地将其转换为右外连接。

也就是说,我实际上会选择您列出的第二个版本,因为这将允许您在 VALID = 'Y' 上使用索引(如果该索引存在),而上述版本可能由于 OR 而不会使用该索引在 where 子句中。

关于Oracle 带过滤器的全外连接 (ANSI) 未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17300789/

相关文章:

html - 访问过滤结果 Angular 6

sql - 没有分组依据的 Oracle 结果

sql - 使用 SQL 的时间表分配

database - 从 Oracle 11g 中给定的 url 下载文件并将其保存到 blob 类型列中的过程

sql - Toad:表格自动完成功能不起作用

java - Oracle数据库: access multiple database schemas

python - 使用外键作为参数在 Django 中过滤对象

json - 无法在flutter中过滤listview.builder的列表

Oracle STANDARD_HASH 结果在使用不同平台时显示不同的结果

sql - 在Oracle中,您可以创建仅在数据库运行时存在的表吗?