我正在尝试学习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;
我认为这样做是:
加入家庭和物种作为正确的联合,因此它带来了每个物种,但不是那些没有物种的家庭。因此,如果一个物种没有被归类为一个家庭,那么它将在家庭中出现无效。
然后,加入王国的结果作为左联,所以它带来了每个王国,即使在那个王国上没有归类的家庭或物种。
我错了吗?这不应该告诉我那些尚未归类的物种吗?如果我做内部查询它会带来我想要的东西。我在分组的时候有问题吗?
答案 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吗?