join是mysql中一个基础的关键词,一般在多表连接查询中使用,这里做一下总结

1、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)

 2、JOIN解析说明

我们先准备实验例子(mysql 版本:mysql  Ver 14.12 Distrib 5.0.95, for redhat-linux-gnu (i686) using readline 5.1)

CREATE TABLE `test_join_a` (
`id` bigint(20) NOT NULL DEFAULT '',
`name` varchar(200),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `test_join_b` (
`id` bigint(20) NOT NULL DEFAULT '',
`sex` varchar(200),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `test_join_c` (
`id` bigint(20) NOT NULL DEFAULT '',
`class` varchar(200),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into test_join_a (id) values (1);
insert into test_join_a (id, name) values (2, "abc");
insert into test_join_a (id, name) values (3, "abcd");
insert into test_join_a (id, name) values (4, "abcde"); insert into test_join_b (id) values (1);
insert into test_join_b (id, sex) values (2, "abc");
insert into test_join_b (id, sex) values (3, "abc"); insert into test_join_c (id) values (1);
insert into test_join_c (id, class) values (2, "abc");
insert into test_join_c (id, class) values (3, "abc");

a、关于LEFT JOIN

对于 A LEFT JOIN (B, C)  ON join_condition ,A表m,B表n, C表t 条记录   【说明:由于未发现专业术语描述A,B,C三表区别,此处,将A表暂称基础表,B,C表称附加表】
    * 以A表为基础表,从B表和C表中挑选符合ON join_condition条件的数据,如果没有符合的,则附加表(B,C)的列对应的行设置为NULL。
    * 通过这种连接方式,查询后的数据条数,最多为 m * n * t条, 最少为 m条   
    
    同理,对于(A, B) LEFT JOIN C ON join_condition
    * 以A, B表为基础表,从C表中挑选符合ON join_condition条件的数据,如果没有符合的,则附加表(C)的列对应的行设置为NULL。
    * 通过这种连接方式,查询后的数据条数,最多为 m * n * t条, 最少为 m * n条
    
    在LEFT JOIN 和 RIGHT JOIN 中,ON 子句后还有 WHERE 子句的筛选条件,区别在于
    1、where子句可以省略,ON 子句不能省略,如果不用ON join_condition,则可以使用ON 1=1 或者 ON 1
    2、ON join_condtion 会以基础表的笛卡尔积为基础,附加表没有符合ON join_condtion的记录,则将附加表列对应的行设为NULL。
    3、where 子句会将 ON join_condition生成的虚拟表做筛选。所以通过where子句后,获取的记录数,最少为 0条

 注意: NULL=NULL 既不符合 join的on condition 也不符合 where子句的筛选   
    
     下面是两个实验过程,a表4条记录,b表3条,c表3条:

  1、可以看到生成记录条数4 * 3 * 3 = 36 条

mysql> select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from test_join_a a left join (test_join_b b, test_join_c c) on 1=1;
+-----+-------+------+------+------+-------+
| aid | name | bid | sex | cid | class |
+-----+-------+------+------+------+-------+
| 1 | NULL | 1 | NULL | 1 | NULL |
| 1 | NULL | 1 | NULL | 2 | abc |
| 1 | NULL | 1 | NULL | 3 | abc |
| 1 | NULL | 2 | abc | 1 | NULL |
| 1 | NULL | 2 | abc | 2 | abc |
| 1 | NULL | 2 | abc | 3 | abc |
| 1 | NULL | 3 | abc | 1 | NULL |
| 1 | NULL | 3 | abc | 2 | abc |
| 1 | NULL | 3 | abc | 3 | abc |
| 2 | abc | 1 | NULL | 1 | NULL |
| 2 | abc | 1 | NULL | 2 | abc |
| 2 | abc | 1 | NULL | 3 | abc |
| 2 | abc | 2 | abc | 1 | NULL |
| 2 | abc | 2 | abc | 2 | abc |
| 2 | abc | 2 | abc | 3 | abc |
| 2 | abc | 3 | abc | 1 | NULL |
| 2 | abc | 3 | abc | 2 | abc |
| 2 | abc | 3 | abc | 3 | abc |
| 3 | abcd | 1 | NULL | 1 | NULL |
| 3 | abcd | 1 | NULL | 2 | abc |
| 3 | abcd | 1 | NULL | 3 | abc |
| 3 | abcd | 2 | abc | 1 | NULL |
| 3 | abcd | 2 | abc | 2 | abc |
| 3 | abcd | 2 | abc | 3 | abc |
| 3 | abcd | 3 | abc | 1 | NULL |
| 3 | abcd | 3 | abc | 2 | abc |
| 3 | abcd | 3 | abc | 3 | abc |
| 4 | abcde | 1 | NULL | 1 | NULL |
| 4 | abcde | 1 | NULL | 2 | abc |
| 4 | abcde | 1 | NULL | 3 | abc |
| 4 | abcde | 2 | abc | 1 | NULL |
| 4 | abcde | 2 | abc | 2 | abc |
| 4 | abcde | 2 | abc | 3 | abc |
| 4 | abcde | 3 | abc | 1 | NULL |
| 4 | abcde | 3 | abc | 2 | abc |
| 4 | abcde | 3 | abc | 3 | abc |
+-----+-------+------+------+------+-------+
36 rows in set (0.00 sec)

 

  2、筛选符合条件的记录,如果没有符合的,则设置为NULL,参看实验表中aid=1,3, 4情况。

mysql> select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from test_join_a a left join (test_join_b b, test_join_c c) on 
a.name=b.sex;
+-----+-------+------+------+------+-------+
| aid | name | bid | sex | cid | class |
+-----+-------+------+------+------+-------+
| 1 | NULL | NULL | NULL | NULL | NULL |
| 2 | abc | 2 | abc | 1 | NULL |
| 2 | abc | 2 | abc | 2 | abc |
| 2 | abc | 2 | abc | 3 | abc |
| 2 | abc | 3 | abc | 1 | NULL |
| 2 | abc | 3 | abc | 2 | abc |
| 2 | abc | 3 | abc | 3 | abc |
| 3 | abcd | NULL | NULL | NULL | NULL |
| 4 | abcde | NULL | NULL | NULL | NULL |
+-----+-------+------+------+------+-------+
9 rows in set (0.00 sec)

  3、针对 (A, B) LEFT JOIN C ON join_condition 的情况,筛选符合条件的记录,以A,B表的笛卡尔积为基础,查找C中符合 on join_condition的记录数,如果没有,则将C中对应列的行值设置未NULL。

mysql> select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from (test_join_a a, test_join_b b) left join  test_join_c c on b.id>5;
+-----+-------+-----+------+------+-------+
| aid | name | bid | sex | cid | class |
+-----+-------+-----+------+------+-------+
| 1 | NULL | 1 | NULL | NULL | NULL |
| 1 | NULL | 2 | abc | NULL | NULL |
| 1 | NULL | 3 | abc | NULL | NULL |
| 2 | abc | 1 | NULL | NULL | NULL |
| 2 | abc | 2 | abc | NULL | NULL |
| 2 | abc | 3 | abc | NULL | NULL |
| 3 | abcd | 1 | NULL | NULL | NULL |
| 3 | abcd | 2 | abc | NULL | NULL |
| 3 | abcd | 3 | abc | NULL | NULL |
| 4 | abcde | 1 | NULL | NULL | NULL |
| 4 | abcde | 2 | abc | NULL | NULL |
| 4 | abcde | 3 | abc | NULL | NULL |
+-----+-------+-----+------+------+-------+
12 rows in set (0.00 sec)

  4、可以看出ON condition的执行在WHERE之前,ON condition会形成虚拟表。

mysql> explain select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from test_join_a a left join (test_join_b b, test_join_c c) on b.id>5 where b.id>5;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------------+
| 1 | SIMPLE | b | range | PRIMARY | PRIMARY | 8 | NULL | 1 | Using where |
| 1 | SIMPLE | c | ALL | NULL | NULL | NULL | NULL | 3 | Using join buffer |
| 1 | SIMPLE | a | ALL | NULL | NULL | NULL | NULL | 4 | Using join buffer |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------------+
3 rows in set (0.00 sec)

  5、WHERE 对虚拟表的筛选和ON条件是不一样的,ON condition会保存基础表的每条数据,附加表中没有符合的,则将附加表列设置为NULL,WHERE 只是筛选符合WHERE 子句的记录。 (可以从下面的第三次查询的结果看出,查询的是通过ON condition形成的虚拟表)

mysql> select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from test_join_a a left join (test_join_b b, test_join_c c) on b.id>5;
+-----+-------+------+------+------+-------+
| aid | name | bid | sex | cid | class |
+-----+-------+------+------+------+-------+
| 1 | NULL | NULL | NULL | NULL | NULL |
| 2 | abc | NULL | NULL | NULL | NULL |
| 3 | abcd | NULL | NULL | NULL | NULL |
| 4 | abcde | NULL | NULL | NULL | NULL |
+-----+-------+------+------+------+-------+
4 rows in set (0.00 sec) mysql> select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from test_join_a a left join (test_join_b b, test_join_c c) on b.id>5 where b.id>5;
Empty set (0.00 sec) mysql> select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from test_join_a a left join (test_join_b b, test_join_c c) ON a.name=b.sex where b.sex is NULL;
+-----+-------+------+------+------+-------+
| aid | name  | bid  | sex  | cid  | class |
+-----+-------+------+------+------+-------+
|   1 | NULL  | NULL | NULL | NULL | NULL  |
|   3 | abcd  | NULL | NULL | NULL | NULL  |
|   4 | abcde | NULL | NULL | NULL | NULL  |
+-----+-------+------+------+------+-------+

6、NULL=NULL 既不符合 join的on condition 也不符合 where子句的筛选

mysql> select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from test_join_a a left join (test_join_b b, test_join_c c) ON a.name=b.sex;
+-----+-------+------+------+------+-------+
| aid | name | bid | sex | cid | class |
+-----+-------+------+------+------+-------+
| 1 | NULL | NULL | NULL | NULL | NULL |
| 2 | abc | 2 | abc | 1 | NULL |
| 2 | abc | 2 | abc | 2 | abc |
| 2 | abc | 2 | abc | 3 | abc |
| 2 | abc | 3 | abc | 1 | NULL |
| 2 | abc | 3 | abc | 2 | abc |
| 2 | abc | 3 | abc | 3 | abc |
| 3 | abcd | NULL | NULL | NULL | NULL |
| 4 | abcde | NULL | NULL | NULL | NULL |
+-----+-------+------+------+------+-------+
9 rows in set (0.00 sec) mysql> select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from test_join_a a left join (test_join_b b, test_join_c c) ON a.name=b.sex where a.name=b.sex;
+-----+------+------+------+------+-------+
| aid | name | bid | sex | cid | class |
+-----+------+------+------+------+-------+
| 2 | abc | 2 | abc | 1 | NULL |
| 2 | abc | 3 | abc | 1 | NULL |
| 2 | abc | 2 | abc | 2 | abc |
| 2 | abc | 3 | abc | 2 | abc |
| 2 | abc | 2 | abc | 3 | abc |
| 2 | abc | 3 | abc | 3 | abc |
+-----+------+------+------+------+-------+
6 rows in set (0.00 sec)

b、关于RIGHT JOIN

  right join和 left join类似,区别在于
  1、对于 A right join (B, C) on join_condition ,会以 B,C表为基础表,A表为附加表
  2、对于 (B, C) right join A on join_condition ,会以 A 表为基础表,B,C表为附加表

C、关于JOIN

JOIN与LEFT JOIN 和RIGHT JOIN的区别在于 JOIN 不区别左右基础表,可以认为他的ON condition 退化成where 子句形式,
例如:对于下面的SQL

select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from (test_join_a a ,test_join_b b) join test_join_c c ON a.name=b.sex;

结果上等价于

select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from (test_join_a a ,test_join_b b) join test_join_c c ON  1=1 where a.name=b.sex;

同时对于 A JOIN (B, C) 等价于 (A,B) JOIN C

关于JOIN的解析过程,我们可以理解成, 将A,B,C表做笛卡尔积,构成新的虚拟表, ON condition转化成where 子句,结合后面的where 子句做筛选,得出筛选结果。

我们来看一下实验情况:

mysql> explain select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from (test_join_a a ,test_join_b b) join test_join_c c ON a.name=b.sex;
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
| 1 | SIMPLE | b | ALL | NULL | NULL | NULL | NULL | 3 | |
| 1 | SIMPLE | c | ALL | NULL | NULL | NULL | NULL | 3 | Using join buffer |
| 1 | SIMPLE | a | ALL | NULL | NULL | NULL | NULL | 4 | Using where; Using join buffer |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
3 rows in set (0.00 sec) mysql> explain select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from (test_join_a a ,test_join_b b) join test_join_c c ON 1=1 where a.name=b.sex;
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
| 1 | SIMPLE | b | ALL | NULL | NULL | NULL | NULL | 3 | |
| 1 | SIMPLE | c | ALL | NULL | NULL | NULL | NULL | 3 | Using join buffer |
| 1 | SIMPLE | a | ALL | NULL | NULL | NULL | NULL | 4 | Using where; Using join buffer |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
3 rows in set (0.00 sec)

可以看出,两个sql的explain结果是一样的,拥有相同的执行计划

我们再看看这两个sql的执行结果

mysql> select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from (test_join_a a ,test_join_b b) join test_join_c c ON a.name=b.sex;
+-----+------+-----+------+-----+-------+
| aid | name | bid | sex | cid | class |
+-----+------+-----+------+-----+-------+
| 2 | abc | 2 | abc | 1 | NULL |
| 2 | abc | 3 | abc | 1 | NULL |
| 2 | abc | 2 | abc | 2 | abc |
| 2 | abc | 3 | abc | 2 | abc |
| 2 | abc | 2 | abc | 3 | abc |
| 2 | abc | 3 | abc | 3 | abc |
+-----+------+-----+------+-----+-------+
6 rows in set (0.00 sec) mysql> select a.id as aid, a.name, b.id as bid, b.sex, c.id as cid, c.class from (test_join_a a ,test_join_b b) join test_join_c c ON 1=1 where a.name=b.sex;
+-----+------+-----+------+-----+-------+
| aid | name | bid | sex | cid | class |
+-----+------+-----+------+-----+-------+
| 2 | abc | 2 | abc | 1 | NULL |
| 2 | abc | 3 | abc | 1 | NULL |
| 2 | abc | 2 | abc | 2 | abc |
| 2 | abc | 3 | abc | 2 | abc |
| 2 | abc | 2 | abc | 3 | abc |
| 2 | abc | 3 | abc | 3 | abc |
+-----+------+-----+------+-----+-------+
6 rows in set (0.00 sec)

  

mysql中的JOIN用法总结的更多相关文章

  1. mysql中explain的用法

    mysql中explain的用法 最近在做性能测试中经常遇到一些数据库的问题,通常使用慢查询日志可以找到执行效果比较差的sql,但是仅仅找到这些sql是不行的,我们需要协助开发人员分析问题所在,这就经 ...

  2. mysql中event的用法详解

    一.基本概念mysql5.1版本开始引进event概念.event既“时间触发器”,与triggers的事件触发不同,event类似与linux crontab计划任务,用于时间触发.通过单独或调用存 ...

  3. mysql中limit的用法实例解析

    mysql中limit的用法解析. 在mysql中,select * from table limit m,n.其中m是指记录开始的index,从0开始,n是指从第m条开始,取n条. 例如: mysq ...

  4. Mysql中limit的用法详解

    Mysql中limit的用法详解 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,为我们提供了limit这样一个功能. SELECT * FROM table LIMIT [offset ...

  5. MySQL中CONCAT()的用法

    MySQL中CONCAT()的用法 在日常开发过程中,特别是在书写接口的时候,经常会遇到字符串拼接的情况,比如在返回图片数据时,数据库里往往存储的是相对路径,而接口里一般是存放绝对地址,这就需要字符串 ...

  6. mysql中FIND_IN_SET函数用法

    本篇文章主要介绍mysql中FIND_IN_SET函数用法,用来精确查询字段中以逗号分隔的数据 以及其与 like 和 in 的区别 1.问题发现 之前在做工作任务时有这么一个需求:需要用接口所传的服 ...

  7. mysql中left join right join inner join用法分析

    mysql数据库中的关联查询,基本都会用到left join,right join,inner join等查询方式,今天来说说这三种用法的区别 1.创建表test1,test2,插入测试数据 #创建表 ...

  8. mysql学习之join用法

    转载  一张图看懂 SQL 的各种 join 用法 一.JOIN 使用介绍 下面例子使用的数据表如下: -- ---------------------------- -- Table structu ...

  9. mysql中in的用法详解

    一.基础用法 mysql中in常用于where表达式中,其作用是查询某个范围内的数据. select * from where field in (value1,value2,value3,-) 当 ...

随机推荐

  1. hibernate和struts2实现分页功能

    1.DAO层接口的设计,定义一个PersonDAO接口,里面声明了两个方法: public interface PersonDAO { public List<Person> queryB ...

  2. -_-#【AJAX】XMLHttpRequest

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. 【转】Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果

    原文网址:http://blog.csdn.net/xiaanming/article/details/17539199 转帖请注明本文出自xiaanming的博客(http://blog.csdn. ...

  4. 酷派D530刷机指引之官方ROM

    刷机前的准备工作 刷官方ROM的大致过程就是:先手机连接电脑,然后在电脑上运行刷机工具,然后那个刷机工具就会把你选择的ROM装到手机里面,然后就没有然后了. 所以在刷机之前,硬件方面需要准备好: 充满 ...

  5. [转]Java Daemon Startup Script

    How to start a Java program as a Linux daemon with an /etc/init.d script. See also: http://www.sourc ...

  6. 《算法问题实战策略》-chaper14-整数论

    Lucas定理: 在组合计数问题中,我们常面临组合数C(n,m)过大而无法直接计算的困境,那么这里的Lucas定理给出了一个较大组合数进行取余运算的一种递归算法. 什么是Lucas定理? Lucas定 ...

  7. des加密解密源码 C# key值问题

    公司协议安全需求.需要对传输内容做des.md5加密. 因为是新人.刚交给我这个任务的时候有点眩晕.就开始在网上找各种des加密的内容.因为不懂以为需要把原理也搞明白,最后误了时间.把自己也搞糊涂了. ...

  8. Hotel - poj 3667(求连续子区间)

    题意:有两种操作 1,从左往右找一个区间是 D 的连续序列,然后覆盖,返回区间最前面的数,如果没有输出0 2, 释放从L开始连续D的区间 分析:就是从左往右查找一个D的连续区间,可以使用三个值操作ls ...

  9. CF380C Sereja and Brackets [想法+线段树]

    题意: 给出一串括号 给出一些询问,问某个区间[l,r]内的能合法匹配的括号数有多少个 分析: 我们能够实现处理两个数组 sum[i] 1....i中已经能匹配的右括号的数目 left[i] 1... ...

  10. linux下负载均衡(LVS安装与配置)【转】

    一.LVS的三种包转发方式      LVS提供了三种包转发方式:NAT(网络地址映射).IP Tunneling(IP隧道).Direct Routing(直接路由)     不同的转发模式决定了不 ...