2012-03-28 33 views
5

我正在尝试学习ansi-92 SQL标准,但我似乎并没有完全理解它(我对ansi-89标准以及数据库一般都不熟悉)。我误解了联结吗?

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

  • 有可能是没有物种和家庭的王国。
  • 可能有家庭没有物种也没有kindgoms。
  • 有可能是没有王国或家庭的物种。

为什么会发生这种情况?

说的生物学家发现一个新物种,但他并没有分为王国或家庭这一点,创建一个新的家族,有没有种,是不知道什么王国它应该属于等

这里是一个小提琴(看最后一个查询):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. 然后,加入王国,结果作为左连接,因此它带来了每个王国,即使没有家族或物种归于该王国。

我错了吗?这不应该显示那些未被分类的物种吗?如果我做内部查询它会带来我想要的。我在分组的东西有问题吗?

+0

这是否混乱与Oracle不?我的查询中的查询优化,是括号不必要的?我得到相同的结果吗? oracle的命令是什么? – Roger 2012-03-28 05:41:15

+0

@outis我必须恭敬地不同意这种连接语法不能嵌套。 [我相信,这篇文章讨论这个话题(http://tonyhasler.wordpress.com/2009/02/22/parentheses-in-ansi-join-syntax/),并得出结论:可以使用括号明确的顺序连接多个表时的操作。 – 2012-03-28 05:55:05

+0

@MichaelFredrickson:我纠正了。它就是SQL/Foundation§7.6。 – outis 2012-03-28 07:38:41

回答

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 joinfull 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; 

我认为这将是preferrable,因为你消除RIGHT JOIN,通常在为是风格差皱起了眉头......和括号,这可能会非常棘手,为人们正确分析判断的结果会是什么。

+0

非常感谢,现在事情更清楚了。感谢您抽出时间:) – Roger 2012-03-28 05:33:16

+0

尽管还有一个问题;阅读我对外部问题的评论。括号是否不必要?这是否与Oracle优化器混淆? – Roger 2012-03-28 05:36:33

+0

我不同意@outis ...但我主要在SQL Server中工作,所以这在Oracle中可能会有所不同。但是,根据我的经验,括号可以影响结果以及执行计划。 [这里有一个我相信在Oracle中证实了这一点的源代码。](http://tonyhasler.wordpress.com/2009/02/22/parentheses-in-ansi-join-syntax/)...我不确定如何在不使用括号的情况下重组查询(可能必须将其更改为子选择),但如果可以,您可以比较两种方法之间的执行计划以确保您的原始方法是可以接受的 – 2012-03-28 05:51:04

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) 

莫非,你互换表especie efamilia和enombre?

+0

我不是在寻找内部连接,无论如何谢谢。 – Roger 2012-03-28 05:37:32

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

1

如果你想查询重写只有你所拥有的最轻微的变化,你可以改变LEFT加入到FULL加入。您可以进一步去除多余的括号和r.rnombre = f.freinoON条件:

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  
+0

我想要最好的结果,我不在乎是否需要重新编写它;什么是最好的数据库,为什么? – Roger 2012-03-28 15:37:45

+0

既然你只想要拥有物种的家庭,那么就不需要'r.rnombre = f.freino'。从Join结构中删除括号可能有或没有任何作用,这取决于DBMS(并且我不是Oracle的专家,对此有任何意见)。 – 2012-03-28 15:50:37

+0

只是未成年人而已。这个查询(以及迈克尔接受的查询)将不包括具有王国(但没有物种)的家族。 – 2012-03-28 15:53:19