我是否误解了加入?

时间:2012-03-28 04:59:56

标签: sql oracle outer-join

我正在尝试学习ansi-92 SQL标准,但我似乎并不完全理解它(我也是ansi-89标准的新手以及一般的数据库)。

在我的例子中,我有三个表王国 - <家庭 - <物种(生物学分类)。

  • 可能有没有物种或家庭的王国。
  • 可能有没有物种的家庭,也没有善良的家庭。
  • 可能有没有王国或家庭的物种。

为什么会这样?

说一位生物学家,找到一个新物种,但他没有把它归类为一个王国或一个家庭,创造了一个没有物种的新家庭,并且不确定它应该属于哪个王国等等。

这是一个小提琴(见最后一个查询):http://sqlfiddle.com/#!4/015d1/3

我想做一个查询,检索每个王国,每个物种,但不是那些没有物种的家庭,所以我做到了。

    select *
    from reino r
         left join (
             familia f             
             right join especie e
                 on f.fnombre = e.efamilia
                 and f.freino = e.ereino
         ) on r.rnombre = f.freino 
           and r.rnombre = e.ereino;

我认为这样做是:

  1. 加入家庭和物种作为正确的联合,因此它带来了每个物种,但不是那些没有物种的家庭。因此,如果一个物种没有被归类为一个家庭,那么它将在家庭中出现无效。

  2. 然后,加入王国的结果作为左联,所以它带来了每个王国,即使在那个王国上没有归类的家庭或物种。

  3. 我错了吗?这不应该告诉我那些尚未归类的物种吗?如果我做内部查询它会带来我想要的东西。我在分组的时候有问题吗?

4 个答案:

答案 0 :(得分:2)

您对#1的描述正确...您的查询问题出在第2步。

当你从王国到(家庭和物种)做left join时,即使没有匹配(家庭和物种),你也要求每个王国......但是,这不会归还任何没有匹配王国的(家庭和物种)组合。

仔细查询将是:

select *
    from reino r
         full join (
             familia f             
             right join especie e
                 on f.fnombre = e.efamilia
                 and f.freino = e.ereino
         ) on r.rnombre = f.freino 
           and r.rnombre = e.ereino;

请注意,left join已替换为full join ...

然而,这仅返回与物种相关的家庭......它不会返回任何与王国相关但不与物种相关的家庭。

重新阅读你的问题之后,这实际上是你想要的......


编辑:进一步考虑,您可以像这样重写您的查询:

select *
from 
    especie e
    left join familia f 
        on f.fnombre = e.efamilia
        and f.freino = e.ereino
    full join reino r
        on r.rnombre = f.freino 
        and r.rnombre = e.ereino;

我认为这是首选,因为你消除了RIGHT JOIN,这通常是因为风格不好而不赞成的......以及括号,这对于人们正确解析以确定结果可能是棘手的将是。

答案 1 :(得分:2)

如果这有帮助:

  

从关系上讲,[OUTER JOIN是一种猎枪婚姻:它   迫使表成为一种联盟 - 是的,我的意思是联盟,而不是联合 - 甚至   当有问题的表不符合通常的要求时   为了工会。它实际上是通过填充一个或   在进行并集之前,这两个表都带有空值,从而生成   毕竟它们符合那些通常的要求。但是没有   为什么不应该使用适当的值来填充填充   的空值,如下例所示:

SELECT SNO , PNO 
FROM   SP 
UNION  
SELECT SNO , 'nil' AS PNO 
FROM   S 
WHERE  SNO NOT IN ( SELECT SNO FROM SP )

以上相当于:

SELECT SNO , COALESCE ( PNO , 'nil' ) AS PNO 
FROM   S NATURAL LEFT OUTER JOIN SP

来源: SQL and Relational Theory: How to Write Accurate SQL Code By C. J. Date

答案 2 :(得分:1)

如果您希望仅根据您所拥有的内容进行最轻微的更改来重写查询,则可以将LEFT联接更改为FULL联接。您可以从r.rnombre = f.freino条件中进一步删除冗余括号和ON

select *
from reino r
     full join                      --- instead of LEFT JOIN
         familia f             
         right join especie e
             on f.fnombre = e.efamilia
             and f.freino = e.ereino
       on r.rnombre = e.ereino;
                                ---removed the:    r.rnombre = f.freino    

答案 3 :(得分:0)

尝试使用它:

select * 
from reino r 
join especie e on (r.rnombre = e.ereino) 
join familia f on (f.freino = e.ereino and f.fnombre = e.efamilia)
可能是这样,你在表格中交换了familia和nombre吗?