[转载] 多表连接(join)小结
原文地址:http://www.cnblogs.com/ybwang/archive/2010/06/04/1751727.html
参考:《sql查询初学者指南》第二版,机械工业出版社
基础
内链接就是对表A和表B以元组为单位做一个笛卡尔积,记为表C,然后在C中挑选出满足符合on 语句后边的限制条件的条目。
左连接就是在内连接的基础上,将A中有但C中没有的元组也加上。由于C的列数比A的列数多,所以这新增的元组左边照搬a,右边为null。
右链接就是在内连接的基础上,将B中有但C中没有的元组也加上。由于C的列数比B的列数多,所以这新增的元组右边照搬B,左边为null。
所谓的full join ,就是在join的结果d后边先加上left join 要加的项,再加上right join 要加的项
所谓的交叉连接(select * from tableName1 cross join tableName2)和select * from tableName1, tableName2是一样的,都是得到笛卡尔积。可以用select * from table1,table2 where....模拟join操作。
所谓的自身连接是指同一个表自己与自己进行连接。这种一元连接通常用于从自反关系(也称作递归关系)中抽取数据。例如人力资源数据库中雇员与老板的关系。
直接写join就是内连接,相当于inner join, inner可省
写left join或者right join就是外连接,outer可省
例子
有两表A和B
A
B
下面是一些select操作
select * from A cross join A
select * from A join B on A.name = B.name
就是对笛卡尔积,也即上边的cross join的结果进行进一步筛选,选出满足A.name=B.name的行。
只有两行符合条件
在上衣select语句的基础上增加了一行
select * from A left join B on A.name = B.name
同上
select * from A right join B on A.name = B.name
select * from A full join B on A.name = B.name
进阶
重要理论依据:
在可以指定一个表名的任何地方,都可以指定一个括号括起来的join子句。
在两个表的一个完整join语句出现的任何一个地方,我们都可以只用一个表名来代替它。
所谓“两个表的一个完整join语句”也即“join子句”,就是指如“A join B on A.a= B.b”这样一个完整的句子
比如:欲连接ABCDE五个表
可以这样:
Select * from A inner join(((
B inner join C on B.b = C.c)
inner join D on B.b = D.d)
inner join E on D.d = E.e)
on A.a = E.e
也可以这样:
select * from (((
A inner join B on A.a = B.b)
inner join C on C.c = A.a)
inner join D on D.d = C.c)
inner join E
on E.e = D.d
也可以这样:
select * from
A inner join B on A.a = B.b
inner join C on C.c = A.a
inner join D on D.d = C.c
inner join E on E.e = D.d
我们可以先把A和B连接起来,然后将结果与C连接,当然,如果C只和B相关而不和A相关的话,我们也可以先把B和C连接起来,结果再与A连接,只要保持关系是正确的,你可以以任意方式来定义嵌套的join。
然而大多数数据库系统会分析整个from子句,然后尝试确定组合连接表的最有效方式,也就是说数据库不不一定会从最里边的括号开始执行查询。这很可能打乱你的逻辑设计,得到意外的结果。
另外,一些数据库系统中的优化器对于join定义的顺序很敏感。如果你发现使用很多join的查询在一个较大的数据库上执行花很长时间,通过改变sql语句中的join顺序很可能能够使它运行的更快。
注意:有时候,你只需要A和C表中的一部分数据,但A和C只有通过B才能发生关系,那么你依然要先将A和B连接,然后再连接C
一个比较全面的例子:
select RCFiltered.ClassName, R.RecipeTitle
from
(select RecipeClassId,
RecipeClassDescription as ClassName
From Recipe_Classes as RC
where RC.ClassName = 'Salads' or RC.ClassName = 'Soup' or Rc.ClassName = 'Main Course')
as RCFiltered
left outer join Recipes as R
on RCFiltered.RecipeClassId = R.RecipeClassId
这个例子的内涵:
1. 在大多数sql的实现中,我们可以把from子句中的任何表名替换成一条完整的select语句.当然,必须分配一个相关名称。本例中为子select语句分配的名称为RCFiltered,在第7行。
2. 当我们决定以select代替表名的时候,要确保select的结果不仅包含想要出现在最终结果中的列,而且包含需要执行join的列。这就是为什么我们在嵌入的select语句中既看到了RecipeClassId又看到了RecipeClassDescription.
3. 我们给RecipeClassDescription一个别名ClassName,所以在第一行使用了RDFiltered的别名。第一行的select只看到了表RCFiltered,看不到表Recipe_Classes