1

我遇到了一个问题,即带有过滤器的 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 优化器或驱动程序的问题?

4

2 回答 2

2

正如其他人在评论中解释的那样,这是因为您放置过滤器逻辑的位置。因此,您的原始查询将返回所有布偶和所有电话号码,并在 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条款。

于 2013-06-25T16:48:39.080 回答
0

您可能应该使用左外连接而不是完全外连接。

在完全外连接中,您将根据 m.id 和 p.valid 从左到右连接,但您还将返回右侧的所有未连接任何内容的行以及左侧未连接的所有行对任何事情。

于 2013-06-25T15:09:22.897 回答