1 .内联结、外联结、左联结、右联结的含义及区别:
在讲 MySQL 的 Join 语法前还是先回顾一下联结的语法,呵呵,其实连我自己都忘得差不多了,那就大家一起温习吧(如果内容有错误或有疑问,可以来信咨询:陈朋奕 chenpengyi#gmail.com ),国内关于 MySQL 联结查询的资料十分少,相信大家在看了本文后会对 MySQL 联结语法有相当清晰的了解,也不会被 Oracle 的外联结的(“+”号)弄得糊涂了。
在 SQL 标准中规划的( Join )联结大致分为下面四种:
1. 内联结:将两个表中存在联结关系的字段符合联结关系的那些记录形成记录集的联结。
2. 外联结:分为外左联结和外右联结。
左联结 A 、 B 表的意思 就是将表 A 中的全部记录和表 B 中联结的字段与表 A 的联结字段符合联结条件的那些记录形成的记录集的联结,这里注意的是最后出来的记录集会包括表 A 的全部记录。
右联结 A 、 B 表的结果和左联结 B 、 A 的结果是一样的,也就是说:
Select A.name B.name From A Left Join B On A.id=B.id
和 Select A.name B.name From B Right Join A on B.id=A.id 执行后的结果是一样的。
3 .全联结:将两个表中存在联结关系的字段的所有记录取出形成记录集的联结(这个不需要记忆,只要是查询中提到了的表的字段都会取出,无论是否符合联结条件,因此意义不大)。
4 .无联结:不用解释了吧,就是没有使用联结功能呗,也有自联结的说法。
这里我有个比较简便的记忆方法,内外联结的区别是内联结将去除所有不符合条件的记录,而外联结则保留其中部分。外左联结与外右联结的区别在于如果用 A 左联结 B 则 A 中所有记录都会保留在结果中,此时 B 中只有符合联结条件的记录,而右联结相反,这样也就不会混淆了。其实大家回忆高等教育出版社出版的《数据库系统概论》书中讲到关系代数那章(就是将笛卡儿积和投影那章)的内容,相信不难理解这些联结功能的内涵。
2. MySQL 联结( Join )的语法
MySQL 支持 Select 和某些 Update 和 Delete 情况下的 Join 语法,具体语法上的细节有:
table_references:
table_reference [, table_reference] …
table_reference:
table_factor
| join_table
table_factor:
tbl_name [[AS] alias]
[{USE|IGNORE|FORCE} INDEX (key_list)]
| ( table_references )
| { OJ table_reference LEFT OUTER JOIN table_reference
ON conditional_expr }
join_table:
table_reference [INNER | CROSS] JOIN table_factor [join_condition]
| table_reference STRAIGHT_JOIN table_factor
| table_reference STRAIGHT_JOIN table_factor ON condition
| table_reference LEFT [OUTER] JOIN table_reference join_condition
| table_reference NATURAL [LEFT [OUTER]] JOIN table_factor
| table_reference RIGHT [OUTER] JOIN table_reference join_condition
| table_reference NATURAL [RIGHT [OUTER]] JOIN table_factor
join_condition:
ON conditional_expr | USING (column_list)
上面的用法摘自权威资料,不过大家看了是否有点晕呢?呵呵,应该问题主要还在于 table_reference 是什么, table_factor 又是什么?这里的 table_reference 其实就是表的引用的意思,因为在 MySQL 看来,联结就是一种对表的引用,因此把需要联结的表定义为 table_reference ,同时在 SQL Standard 中也是如此看待的。而 table_factor 则是 MySQL 对这个引用的功能上的增强和扩充,使得引用的表可以是括号内的一系列表,如下面例子中的 JOIN 后面括号:
SELECT * FROM t1 LEFT JOIN (t2, t3, t4) ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)
这个语句的执行结果和下面语句其实是一样的:
SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)
这两个例子不仅让我们了解了 MySQL 中 table_factor 和 table_reference 含义,同时能理解一点 CROSS JOIN 的用法,我要补充的是在 MySQL 现有版本中 CROSS JOIN 的作用和 INNER JOIN 是一样的(虽然在 SQL Standard 中是不一样的,然而在 MySQL 中他们的区别仅仅是 INNER JOIN 需要附加 ON 参数的语句,而 CROSS JOIN 不需要)。
既然说到了 ON 语句,那就解释一下吧, ON 语句其实和 WHERE 语句功能大致相当,只是这里的 ON 语句是专门针对联结表的, ON 语句后面的条件的要求和书写方式和 WHERE 语句的要求是一样的,大家基本上可以把 ON 当作 WHERE 用。
大家也许也看到了 OJ table_reference LEFT OUTER JOIN table_reference 这个句子,这不是 MySQL 的标准写法,只是为了和 ODBC 的 SQL 语法兼容而设定的,我很少用, Java 的人更是不会用,所以也不多解释了。
那下面就具体讲讲简单的 JOIN 的用法了。首先我们假设有 2 个表 A 和 B ,他们的表结构和字段分别为:
表 A :
ID | Name |
1 | Tim |
2 | Jimmy |
3 | John |
4 | Tom |
表 B :
ID | Hobby |
1 | Football |
2 | Basketball |
2 | Tennis |
4 | Soccer |
1. 内联结:
Select A.Name B.Hobby from A, B where A.id = B.id ,这是隐式的内联结,查询的结果是:
Name | Hobby |
Tim | Football |
Jimmy | Basketball |
Jimmy | Tennis |
Tom | Soccer |
它的作用和 Select A.Name from A INNER JOIN B ON A.id = B.id 是一样的。这里的 INNER JOIN 换成 CROSS JOIN 也是可以的。
2. 外左联结
Select A.Name from A Left JOIN B ON A.id = B.id ,典型的外左联结,这样查询得到的结果将会是保留所有 A 表中联结字段的记录,若无与其相对应的 B 表中的字段记录则留空,结果如下:
Name | Hobby |
Tim | Football |
Jimmy | Basketball , Tennis |
John |
|
Tom | Soccer |
所以从上面结果看出,因为 A 表中的 John 记录的 ID 没有在 B 表中有对应 ID ,因此为空,但 Name 栏仍有 John 记录。
3. 外右联结
如果把上面查询改成外右联结: Select A.Name from A Right JOIN B ON A.id = B.id ,则结果将会是:
Name | Hobby |
Tim | Football |
Jimmy | Basketball |
Jimmy | Tennis |
Tom | Soccer |
这样的结果都是我们可以从外左联结的结果中猜到的了。
说到这里大家是否对联结查询了解多了?这个原本看来高深的概念一下子就理解了,恍然大悟了吧(呵呵,开玩笑了)?最后给大家讲讲 MySQL 联结查询中的某些参数的作用:
1 . USING (column_list) :其作用是为了方便书写联结的多对应关系,大部分情况下 USING 语句可以用 ON 语句来代替,如下面例子:
a LEFT JOIN b USING (c1,c2,c3) ,其作用相当于下面语句
a LEFT JOIN b ON a.c1=b.c1 AND a.c2=b.c2 AND a.c3=b.c3
只是用 ON 来代替会书写比较麻烦而已。
2 . NATURAL [LEFT] JOIN :这个句子的作用相当于 INNER JOIN ,或者是在 USING 子句中包含了联结的表中所有字段的 Left JOIN (左联结)。
3 . STRAIGHT_JOIN :由于默认情况下 MySQL 在进行表的联结的时候会先读入左表,当使用了这个参数后 MySQL 将会先读入右表,这是个 MySQL 的内置优化参数,大家应该在特定情况下使用,譬如已经确认右表中的记录数量少,在筛选后能大大提高查询速度。
最后要说的就是,在 MySQL5.0 以后,运算顺序得到了重视,所以对多表的联结查询可能会错误以子联结查询的方式进行。譬如你需要进行多表联结,因此你输入了下面的联结查询:
SELECT t1.id,t2.id,t3.id
FROM t1,t2
LEFT JOIN t3 ON (t3.id=t1.id)
WHERE t1.id=t2.id;
但是 MySQL 并不是这样执行的,其后台的真正执行方式是下面的语句:
SELECT t1.id,t2.id,t3.id
FROM t1,( t2 LEFT JOIN t3 ON (t3.id=t1.id) )
WHERE t1.id=t2.id;
这并不是我们想要的效果,所以我们需要这样输入:
SELECT t1.id,t2.id,t3.id
FROM (t1,t2)
LEFT JOIN t3 ON (t3.id=t1.id)
WHERE t1.id=t2.id;
在这里括号是相当重要的,因此以后在写这样的查询的时候我们不要忘记了多写几个括号,至少这样能避免很多错误(因为这样的错误是很难被开发人员发现的)