mysql join

MySQL使用JOIN来连接多个表查询数据,主要使用的JOIN算法只有一种,那就是nested-loop join。

nested-loop join算法实现的机制很简单,就是从驱动表中选取数据作为循环基础数据,然后以这些数据作为查询条件到下一个表中进行查询,如此往复。这个实现机制类似于foreach函数的遍历。因此带来的问题就是连接的表越多,函数嵌套的层数就越多,算法复杂度呈指数级增长。

因此,设计查询要尽量减少连接的表的个数。

驱动表是指:在使用多表嵌套连接时,首先,全表扫描该驱动表,然后用驱动表返回的结果集逐行去匹配被驱动的表(可以利用索引),数据库基于成本可能会选择小表作为驱动表,而被驱动表使用索引进行连接。

JOIN语句的含义是把两张(或者多张)表的属性通过它们的值组合在一起,一般会遇到如下3种连接。

·等值连接([INNER]JOIN)

·左外连接(LEFT JOIN)

·右外连接(RIGHT JOIN)

示例用表见图3-4~图3-6所示。

图3-4 职员表

在部门职员表中,如果是在职员工,那么to_date的值为'9999-01-01'。

图3-5 部门表

图3-6 部门职员表

(1)内连接

内连接(INNER JOIN)是应用程序中普遍应用的“连接”操作,它一般都是默认的连接类型。内连接基于连接谓词将两张表(如A和B)的列组合在一起,从而产生新的结果表。

内连接可以被进一步分为等值连接、自然连接和交叉连接。较常用的是等值连接。

以下是等值连接的示例。

查询目前在职的所有员工的姓名及其所在的部门时可使用如下语句。

输出结果如图3-7所示。

自然连接(natural join)是等值连接的进一步特例化。两表做自然连接时,两表中名称相同的所有列都将被比较,这是隐式的。自然连接得到的结果表中,两表中名称相同的列只出现一次。一般应该避免使用自然连接,因为我们无法指定连接列,且

这种写法隐藏了我们的JOIN关系,如果以后数据模型发生了变化,可能会导致出现非预期的结果。

交叉连接(笛卡儿积) 把表视为行记录的集合,交叉连接即返回这两个集合的笛卡儿积。这其实等价于内连接的连接条件为“永真”,或者连接条件不存在的情况。

示例如下。

图3-7 在职员工的姓名和部门的等值连接

SELECT * FROM a JOIN b;

SELECT * FROM a,b;

SQL定义了两种不同的语法方式来表示“连接”。一种是“显式连接符号”,显式地使用关键字JOIN,另一种是“隐式连接符号”,它使用所谓的“隐式连接符号”。隐式连接符号把需要连接的表放到SELECT语句的FROM部分,并用逗号隔开。这样就构成了一个“交叉连接”,WHERE语句可能会放置一些过滤谓词(过滤条件)。那些过滤谓词在功能上等价于显式连接符号。

如上所述的例子中,查询目前在职的所有员工的姓名及所在部门时,可以写成如下的形式。

它等价于:

ON表达式是任何可以用于WHERE子句的条件表达式,一般来说,你应该只在ON表达式里指定如何JOIN表,而把筛选结果集的条件放到WHERE子句中。

(2)外连接(OUT JOIN)

并未要求连接的两表的每一条记录在对方的表中都必须有一条匹配的记录。连接表保留所有的记录,甚至这条记录没有匹配的记录也要保留。外连接可依据连接表保留左表、右表或全部表的行而进一步分为左外连接、右外连接和全外连接。全外连接一般没有什么意义,MySQL并不直接支持全外连接,但可以通过左右外连接的并集(UNION)来模拟实现。

1)左外连接(LEFT JOIN、LEFT OUTER JOIN)

左外连接也简称为左连接(LEFT JOIN),若A和B两表进行左外连接,那么结果表中将包含“左表”(即表A)的所有记录,即使那些记录在“右表”B中没有符合连接条件的匹配。这就意味着即使ON语句在表B中的匹配项是0条,连接操作也还是会返回一条记录,只不过这条记录中的来自于表B的每一列的值都为NULL。

之前的示例曾演示过插入一些记录(员工号111111、111112、111113、111114)到employees表中,但还没有指定新插入员工记录的部门。现在用如下语句联合查询下雇员表和部门–雇员表。

结果如图3-8所示,可以看到有些员工没有部门,dept_no(部门代码)显示为NULL。

2)右外连接(RIGHT JOIN、RIGHT OUT JOIN)

右外连接也简称右连接(RIGHT JOIN),它与左外连接完全类似,只不过是连接表的顺序相反而已。如果A表右连接B表,那么“右表”B中的每一行在连接表中至少会出现一次。如果B表的记录在“左表”A中未找到匹配行,则连接表中来源于A表中的列的值将设为NULL,示例如下。

实际上,显式的右外连接很少使用,因为它的可读性不佳,所以总是被改写成左连接。

图3-8 查询一些员工的部门

如果JOIN的层次比较多,则需要留意一下可读性,如果不能确定优先级,那么建议使用括号来明确优先级,以避免犯错误。例如,在以下的例子中,由于逗号的优先级比JOIN表达式低,因此可能会导致我们犯错误。

上述代码实际上是:

但这其实并不是我们的本意,应该写成如下的形式(用括号来提升优先级别)。

使用JOIN命令操作表的时候,需要留意如果表按条件筛选的记录是不确定的,可能就会导致非预期的结果。下面以图3-9和图3-10所示的数据为例来进行说明。

图3-9 t1表

图3-10 t2表

对于如下的查询:

由于code='b'在两个表中都可以唯一确定一条记录,因此查询会返回合理的结果(如图3-11所示)。

图3-11 返回正确的结果

而对于如下查询:

由于t2表code='a'会返回多个值。最终的查询结果返回了3条记录(如图3-12所示),因此可能不是我们所需要的结果。

图3-12 返回错误的结果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章