源自MySQL 5.7 官方手册:13.2.9.2 JOIN Syntax

  1. SELECT select_expr
  2. From table_references JOIN...
  3. WHERE...

  如上所示,MySQL支持在table_references后添加JOIN选项作为SELECT语句的一部分,当然也可以在多表的DELETE和UPDATE。

  下面列出了JOIN的详细语法:

  1. table_references:
  2. escaped_table_reference [, escaped_table_reference] ...
  3.  
  4. escaped_table_reference:
  5. table_reference
  6. | { OJ table_reference }
  7.  
  8. table_reference:
  9. table_factor
  10. | joined_table
  11.  
  12. table_factor:
  13. tbl_name [PARTITION (partition_names)]
  14. [[AS] alias] [index_hint_list]
  15. | table_subquery [AS] alias
  16. | ( table_references )
  17.  
  18. joined_table:
  19. table_reference [INNER | CROSS] JOIN table_factor [join_specification]
  20. | table_reference STRAIGHT_JOIN table_factor
  21. | table_reference STRAIGHT_JOIN table_factor ON search_condition
  22. | table_reference {LEFT|RIGHT} [OUTER] JOIN table_reference join_specification
  23. | table_reference NATURAL [{LEFT|RIGHT} [OUTER]] JOIN table_factor
  24.  
  25. join_specification:
  26. ON search_condition
  27. | USING (join_column_list)
  28.  
  29. join_column_list:
  30. column_name [, column_name] ...
  31.  
  32. index_hint_list:
  33. index_hint [, index_hint] ...
  34.  
  35. index_hint:
  36. USE {INDEX|KEY}
  37. [FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
  38. | {IGNORE|FORCE} {INDEX|KEY}
  39. [FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
  40.  
  41. index_list:
  42. index_name [, index_name] ...

一、表引用(table reference)

  一个表引用也被称为一个JOIN表达式。表引用(当它引用分区表时)可能有PARTITION选项,包括一个由逗号分隔的分区,子分区或两者皆有的列表。此选项紧跟在的名字之后,并在任何别名声明之前。此选项的作用是仅从列出的分区或子分区中选择数据行,而且将忽略列表中未命名的任何分区或子分区。see Section 22.5, “Partition Selection”。

  table_factor语法是MySQL对标准SQL中的扩展。标准SQL只接受table_reference,而不是一对括号内的列表。

  如果table_reference项列表中的每个逗号被视为内连接(INNER JOIN),则这是保守的扩展。例如:

  1. SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
  2. ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)

等价于:

  1. SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
  2. ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)

在MySQL中,JOIN,CROSS JOIN,和INNER JOIN 在语义上是等价的,他们可以相互替换。但是在标准SQL中,他们不等价,INNER JOIN与ON搭配使用,CROSS JOIN搭配其它。

  一般来说,在只有INNER JOIN操作的表达式中,括号可以被省略。MySQL还支持嵌套连接,

See Section 8.2.1.7, “Nested Join Optimization”。

  指定索引提示(Index  hints )能够影响MySQL优化器如何使用索引。更多信息,see Section 8.9.4, “Index Hints”.

  优化器提示和optimizer_switch系统变量是影响优化器使用索引的其他方法。See Section 8.9.3, “Optimizer Hints”, and Section 8.9.2, “Switchable Optimizations”。

二、在编写联接时要考虑的一般因素

  2.1

  可以使用tbl_name AS alias_name或tbl_name alias_name对表引用定义别名。

  1. SELECT t1.name, t2.salary
  2. FROM employee AS t1 INNER JOIN info AS t2 ON t1.name = t2.name;
  3.  
  4. SELECT t1.name, t2.salary
  5. FROM employee t1 INNER JOIN info t2 ON t1.name = t2.name;

  2.2

  table_subquery也称为FROM子句中的派生表或子查询。Section 13.2.10.8, “Derived Tables”.

  此类子查询必须包含别名,以便为子查询结果提供表名。一个简单的例子如下:

  1. SELECT * FROM (SELECT 1, 2, 3) AS t1;
  2.  
  3. /*
  4.  
  5. +---+---+---+
  6. | 1 | 2 | 3 |
  7. +---+---+---+
  8. | 1 | 2 | 3 |
  9. +---+---+---+
  10.  
  11. */

  2.3

  在没有连接条件的情况下,INNER JOIN和“,”(逗号)在语义上是等效的——两者都在指定的表之间产生笛卡尔积,也就是说,第一个表中的每一行都连接到第二个表中的每一行。

  但是,逗号运算符的优先级比其它含有“JOIN”的运算符要小。如果在存在连接条件时将逗号连接与其他连接类型混合,则可能会报错:Unknown column 'col_name' in 'on clause' 。对这个问题的处理会在文章的后面讨论。

  与ON一起使用的search_condition是可以在WHERE子句中使用的任何条件表达式。ON子句用于指明如多表如何连接,WHERE子句则限制要包含在结果集中的行。

  2.4

  在LEFT JOIN中,如果在右表中没有匹配ON或者USING中条件的行,则该连接中中的右表的列全都设置为NULL。你可以利用这点来查找左表A中在右表B中没有任何对应项的行:

  1. SELECT left_tbl.*
  2. FROM left_tbl LEFT JOIN right_tbl ON left_tbl.id = right_tbl.id
  3. WHERE right_tbl.id IS NULL;

  这个查询语句会找出左表left_tbl中这样的行:其ID值在右表right_tbl的ID列中不存在。See Section 8.2.1.8, “Outer Join Optimization”.(外连接包括LEFT JOIN和RIGHT JOIN)

  例如,我查找学生表stu中在成绩表sc中没有任何成绩的学生:

  1. select stu.*
    from student as stu left join sc on stu.SId=sc.SId
    where sc.SId is null;
  2.  
  3. /*
  4.  
  5. SId | Sname | Sage | Ssex |
  6. +------+-------+---------------------+------+
  7. | 09 | 张三 | 2017-12-20 00:00:00 | 女 |
  8. | 10 | 李四 | 2017-12-25 00:00:00 | 女 |
  9. | 11 | 李四 | 2017-12-30 00:00:00 | 女 |
  10. | 12 | 赵六 | 2017-01-01 00:00:00 | 女 |
  11. | 13 | 孙七 | 2018-01-01 00:00:00 | 女 |
  12. +------+-------+---------------------+------+
  13.  
  14. */

  当然这里碰到了一个小问题,把查询语句的WHERE条件改成sc.SId=null时,取出的是空集:

  1. select stu.*
  2. from student as stu left join sc on stu.SId=sc.SId
  3. where sc.SId=null;
  4.  
  5. /*
  6.  
  7. Empty set (0.08 sec)
  8.  
  9. */

  在WHERE子句中,column = null永远不会为true,以这种方式使用null无效,要检测值为NULL的列,必须使用IS NULL或列IS NOT NULL。关于NULL的使用有专门的章节:Working with NULL Values。

  2.5

  USING(join_column_list)子句指定两个表中必须拥有的列的列表。如果表a和b都包含列c1,c2和c3,则以下连接将比较两个表中的相应列:

  1. a LEFT JOIN b USING (c1, c2, c3)

  2.6

  两个表的NATURAL [LEFT] JOIN等下于下面的情况:带有USING子句的INNER JOIN或LEFT JOIN,该子句列出了在两个表中都存在的所有的列。

  2.7

  RIGHT JOIN的工作方式类似于LEFT JOIN。为了使代码可以跨数据库移植,建议您使用LEFT JOIN而不是RIGHT JOIN。

  2.8

  语法描述中的{ OJ...},只是为了兼容ODBC。这个花括号必须按字面编写。

  1. SELECT left_tbl.*
  2. FROM { OJ left_tbl LEFT OUTER JOIN right_tbl
  3. ON left_tbl.id = right_tbl.id }
  4. WHERE right_tbl.id IS NULL;

  您可以在{OJ ...}中使用其他类型的连接,例如INNER JOIN或RIGHT OUTER JOIN。这有助于与某些第三方应用程序兼容,但不是官方ODBC语法。

  2.9

  STRAIGHT_JOIN类似于JOIN,只是左表始终在右表之前读取。

  这可以用于连接优化器以次优顺序处理表的那些(少数)情况。 

  一些JOIN示例:

  1. SELECT * FROM table1, table2;
  2.  
  3. SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id;
  4.  
  5. SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id;
  6.  
  7. SELECT * FROM table1 LEFT JOIN table2 USING (id);
  8.  
  9. SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
  10. LEFT JOIN table3 ON table2.id = table3.id;

  Natural join和使用USING的JOIN,包括外连接的变体,是根据SQL-2003的标准进行处理的。

  

  2.10

  NATURAL连接中的冗余列不会显示。

  1. CREATE TABLE t1 (i INT, j INT);
  2. CREATE TABLE t2 (k INT, j INT);
  3. INSERT INTO t1 VALUES(1, 1);
  4. INSERT INTO t2 VALUES(1, 1);
  5. SELECT * FROM t1 NATURAL JOIN t2;
  6. SELECT * FROM t1 JOIN t2 USING (j);

  第一个和第二个SELECT语句中的“j”列,都只会出现一次:

  1. /*
  2.  
  3. +------+------+------+
  4. | j | i | k |
  5. +------+------+------+
  6. | 1 | 1 | 1 |
  7. +------+------+------+
  8.  
  9. +------+------+------+
  10. | j | i | k |
  11. +------+------+------+
  12. | 1 | 1 | 1 |
  13. +------+------+------+
  14.  
  15. */

  冗余列的消除和列的排序都是根据标准SQL进行处理,按下面的顺序展示:

  • 首先,合并两个连接表的相同列,按他们在第一个表中出现的顺序排列;
  • 然后,第一个表所特有的列,按它们在该表中出现的顺序排列;
  • 第三,第二个表所特有的列,它们在该表中出现的顺序;

  取代两个表的相同列的单列是通过使用coalesce(合并)操作来定义的,也就是说,对于两个t1.a和t2.a,得到的单个连接列a被定义为a = COALESCE(t1.a,t2.a):

  1. COALESCE(x, y) = (CASE WHEN x IS NOT NULL THEN x ELSE y END)

  

  如果任何其他的join操作,则连接的结果列由参与连接的表的所有列的串联组成。合并的列的定义结果是,对于外连接,如果两列中的一列始终为NULL,则合并列包含非NULL列的值。如果两列都不为NULL或者都为NULL,两个公共列具有相同的值,因此选择哪一列作为合并列的值就无关紧要了。解释这一点的一种简单方法是考虑外连接的合并列由JOIN的内部表的公共列表示。

  假设表t1(a,b)和t2(a,c)具有以下内容:

  1. /*
  2.  
  3. t1 t2
  4. ---- ----
  5. 1 x 2 z
  6. 2 y 3 w
  7.  
  8. */

  那么下面这个JOIN,列a包含的是t1.a的值:

  1. SELECT * FROM t1 NATURAL LEFT JOIN t2;
  2.  
  3. +------+------+------+
  4. | a | b | c |
  5. +------+------+------+
  6. | 1 | x | NULL |
  7. | 2 | y | z |
  8. +------+------+------+

  而下面的JOIN,恰好相反,a列包含的是t2.a的值:

  1. SELECT * FROM t1 NATURAL RIGHT JOIN t2;
  2. +------+------+------+
  3. | a | c | b |
  4. +------+------+------+
  5. | 2 | z | y |
  6. | 3 | w | NULL |
  7. +------+------+------+

  将这些结果与JOIN ... ON的等效查询进行比较:

  1. SELECT * FROM t1 LEFT JOIN t2 ON (t1.a = t2.a);
  2.  
  3. +------+------+------+------+
  4. | a | b | a | c |
  5. +------+------+------+------+
  6. | 1 | x | NULL | NULL |
  7. | 2 | y | 2 | z |
  8. +------+------+------+------+
  1. SELECT * FROM t1 RIGHT JOIN t2 ON (t1.a = t2.a);
  2.  
  3. +------+------+------+------+
  4. | a | b | a | c |
  5. +------+------+------+------+
  6. | 2 | y | 2 | z |
  7. | NULL | NULL | 3 | w |
  8. +------+------+------+------+

  2.11

  USING子句可以使用ON子句进行重写。尽管他们两个很像,但还是有所不同。

  看下下面两个查询:

  1. a LEFT JOIN b USING (c1, c2, c3)
  2. a LEFT JOIN b ON a.c1 = b.c1 AND a.c2 = b.c2 AND a.c3 = b.c3

  在筛选条件上,这两个连接在语义上是一致的。但是在“要为SELECT *扩展显示哪些列”上,这两个连接在语义上并不相同。USING连接选择相应列的合并值,而ON连接选择所有表中的所有列。

  对使用USING的JOIN,SELECT *选择这些值:

  1. COALESCE(a.c1, b.c1), COALESCE(a.c2, b.c2), COALESCE(a.c3, b.c3)

  而使用ON的JOIN,SELECT *选择如下:

  1. a.c1, a.c2, a.c3, b.c1, b.c2, b.c3

  对于内连接,COALESCE(a.c1,b.c1)与a.c1或b.c1相同,因为两列的值都相同。

  对于外连接(例如LEFT JOIN),两列中的一列可以为NULL。该列会从结果中略去。

  2.12

  ON子句只能引用其操作范围内的操作数。

  1. CREATE TABLE t1 (i1 INT);
  2. CREATE TABLE t2 (i2 INT);
  3. CREATE TABLE t3 (i3 INT);
  4.  
  5. SELECT * FROM t1 JOIN t2 ON (i1 = i3) JOIN t3;

  执这个SELECT语句会报错:Unknown column 'i3' in 'on clause' ,因为i3是t3中的一列,它不是ON子句的操作数。

  对此语句进行修改:

  1. SELECT * FROM t1 JOIN t2 JOIN t3 ON (i1 = i3);

  对ON的作用范围进行测试,以下语句均能执行:

  1. SELECT * FROM t1 JOIN t2 JOIN t3 ON (i2 = i3);
  2. Empty set (0.00 sec)
  3.  
  4. SELECT * FROM t1 JOIN t2 JOIN t3 ON (i1 = i2);
  5. Empty set (0.00 sec)

  即ON对其之前的JOIN中的表的列都能引用。

  2.13

  JOIN比逗号操作符拥有更高的优先级,所以下面这个表达式:

  1. t1, t2 JOIN t3

  会被解释为:

  1. (t1, (t2 JOIN t3))

  而不是:

  1. ((t1, t2) JOIN t3)

  这个特点会影响使用ON子句的语句,因为ON子句只能引用JOIN操作的表中的列,优先级会影响对这些操作表的解释。执行如下的语句就报错了:

  1. SELECT * FROM t1,t2 JOIN t3 ON (i1 = i2);
  2.  
  3. ERROR 1054 (42S22): Unknown column 'i1' in 'on clause'

  而这样就能成功执行:

  1. SELECT * FROM (t1,t2) JOIN t3 ON (i1 = i2);
  2.  
  3. Empty set (0.00 sec)

  或者不适用逗号:

  1. SELECT * FROM t1 join t2 JOIN t3 ON (i1 = i2);
  2.  
  3. Empty set (0.00 sec)

  此外,INNER JOIN,CROSS JOIN,LEFT JOIN和RIGHT JOIN混合的语句中,所有这些语句的优先级都高于逗号运算符。

  2.14

  与SQL:2003标准相比,MySQL扩展是MySQL允许您限定NATURAL或USING连接的公共(coalesced合并)列,而标准SQL不允许这样做。

MySQL SELECT语法(三)JOIN语法详解的更多相关文章

  1. mysql备份的三种方式详解

    一.备份的目的 做灾难恢复:对损坏的数据进行恢复和还原需求改变:因需求改变而需要把数据还原到改变以前测试:测试新功能是否可用 二.备份需要考虑的问题 可以容忍丢失多长时间的数据:恢复数据要在多长时间内 ...

  2. Solr系列五:solr搜索详解(solr搜索流程介绍、查询语法及解析器详解)

    一.solr搜索流程介绍 1. 前面我们已经学习过Lucene搜索的流程,让我们再来回顾一下 流程说明: 首先获取用户输入的查询串,使用查询解析器QueryParser解析查询串生成查询对象Query ...

  3. 多表连接的三种方式详解 hash join、merge join、 nested loop

    在多表联合查询的时候,如果我们查看它的执行计划,就会发现里面有多表之间的连接方式.多表之间的连接有三种方式:Nested Loops,Hash Join 和 Sort Merge Join.具体适用哪 ...

  4. 《手把手教你》系列技巧篇(三十二)-java+ selenium自动化测试-select 下拉框(详解教程)

    1.简介 在实际自动化测试过程中,我们也避免不了会遇到下拉选择的测试,因此宏哥在这里直接分享和介绍一下,希望小伙伴或者童鞋们在以后工作中遇到可以有所帮助. 2.select 下拉框 2.1Select ...

  5. (转)总结之:CentOS 6.5 MySQL数据库的基础以及深入详解

    总结之:CentOS 6.5 MySQL数据库的基础以及深入详解 原文:http://tanxw.blog.51cto.com/4309543/1395539 前言 早期MySQL AB公司在2009 ...

  6. MYSQL之数据库初识、安装详解、sql语句基本操作

    目录 MYSQL之数据库初识及安装详解 1.什么是数据库? 1.什么是数据?(data) 2.什么是数据库?(databases,简称DB) 2.为什要用数据库? 3.什么是数据库管理系统?(Data ...

  7. 【转】MySQL用户管理及SQL语句详解

    [转]MySQL用户管理及SQL语句详解 1.1 MySQL用户管理 1.1.1 用户的定义 用户名+主机域 mysql> select user,host,password from mysq ...

  8. MySql绿色版配置及使用详解

    原文:MySql绿色版配置及使用详解 最近在做项目开发时用到了MySql数据库,在看了一些有关MySql的文章后,很快就上手使用了.在使用的过程中还是出现了一些问题,因为使用的是绿色免安装版的MySq ...

  9. MySQL数据库使用mysqldump导出数据详解

    mysqldump是mysql用于转存储数据库的实用程序.它主要产生一个SQL脚本,其中包含从头重新创建数据库所必需的命令CREATE TABLE INSERT等.接下来通过本文给大家介绍MySQL数 ...

  10. mysql数据库分区功能及实例详解

    分区听起来怎么感觉是硬盘呀,对没错除了硬盘可以分区数据库现在也支持分区了,分区可以解决大数据量的处理问题,下面一起来看一个mysql数据库分区功能及实例详解   一,什么是数据库分区 前段时间写过一篇 ...

随机推荐

  1. python+Django+mysql环境搭建

    为什么我的毕业设计还要用到网站啊啊啊啊.什么鬼啊,又要做爱拍拍又要做网站???饶了我啊..我选择狗带.. 网站就用django做吧,毕竟之前做过一个电脑销售网站,希望能借鉴一下经验什么的,不要一切从头 ...

  2. Linux发行版的选择

    1,需要稳定的服务器,选择CentOS 或 RHEL 2,需要自己定制的桌面系统,选择Ubuntu 3,摸索linux 各方面的知识,选择Gentoo 4,需要稳定性高的系统,选择FreeBSD 5, ...

  3. netframework webapi IogAttribute记录request参数和错误信息

    参考博客 https://www.cnblogs.com/hnsongbiao/p/7039666.html 书写LogFilterAttribute public class LogFilterAt ...

  4. arcpy.UpdateCursor和arcpy.da.UpdateCursor计算面积时间的比较

    arcpy.UpdateCursor ####################### import arcpy from arcpy import env import os import sys f ...

  5. maven在整合springmvc+hibernate运行时遇到的一些问题

    在这里大概记录一下自己在搭建的时候遇到的一些小问题. 1,在获取hibernate的sessionFactory对象时报空指针异常,我的常规配置如下:

  6. ExtractIcon function Retrieves a handle to an icon from the specified executable file, DLL, or icon file.

    https://msdn.microsoft.com/zh-cn/vstudio/ms648068(v=vs.90)

  7. 50行代码写的一个插件,破解一个H5小游戏

    小游戏链接:测测你的眼睛对色差的辨识度http://www.webhek.com/post/color-test.html?from=timeline 废话不多说,先放代码: window.onloa ...

  8. TransitionDrawable

    ayerDrawable的一个子类,TransitionDrawable只管理两层的Drawable!两层!两层! 并且提供了透明度变化的动画,可以控制一层Drawable过度到另一层Drawable ...

  9. 阶段5 3.微服务项目【学成在线】_day04 页面静态化_24-页面预览-页面预览测试

    通过nginx转发到预览的地址 重启nginx 添加页面预览按钮 调整下列表的列的宽度

  10. SQL查询交集、并集、差集

     两个表A  和表 T          交集 intersect 并集   UNION SQL:select df from A union select sd from T; 在Union后不加A ...