带筛选器的Oracle完全外部联接(ANSI)未按预期工作

azpvetkf  于 2023-03-22  发布在  Oracle
关注(0)|答案(2)|浏览(148)

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

k2arahey

k2arahey1#

正如其他人在评论中解释的那样,这是因为你把过滤器逻辑放在了哪里。所以你的原始查询将返回所有的muppets和所有的电话号码,并在ID匹配AND valid = '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'或没有匹配到phone表的行。如果你只让where子句“P.VALID = 'Y'",那么你实际上会把它变成一个右外连接。
也就是说,我实际上会选择你列出的第二个版本,因为这将允许你在VALID = 'Y'上使用索引,如果该索引存在的话,上面的版本可能不会使用索引,因为where子句中的OR。

vptzau2j

vptzau2j2#

您可能应该使用左外联接而不是全外联接。
在一个完整的外部连接中,你是基于www.example.com和p.valid从左到右连接m.id,但是你也会返回右边所有没有连接到任何东西的行和左边所有没有连接到任何东西的行。

相关问题