点击上方蓝字关注小姐姐吧从业以来主要在做客户端,用到的数据库都是表结构比较简单的 SQLite,以我那还给老师一大半的 SQL 水平倒也能对付。现在偶尔需要到后台的 SQL Server 里追查一些数据问题,就显得有点捉襟见肘了,特别是各种 JOIN,有时候傻傻分不清楚,于是索性弄明白并做个记录。

前言

在各种问答社区里谈及 SQL 里的各种 JOIN 之间的区别时,最被广为引用的是 CodeProject 上 C.L. Moffatt 的文章 Visual Representation of SQL Joins,他确实讲得简单明了,使用文氏图来帮助理解,效果明显。本文将沿用他的讲解方式,稍有演绎,可以视为该文较为粗糙的中译版。

约定

下文将使用两个数据库表 Table_A 和 Table_B 来进行示例讲解,其结构与数据分别如下:mysql> SELECT * FROM Table_A ORDER BY PK ASC;
+----+---------+
| PK | Value   |
+----+---------+
|  1 | both ab |
|  2 | only a  |
+----+---------+
2 rows in set (0.00 sec)

mysql> SELECT * from Table_B ORDER BY PK ASC;
+----+---------+
| PK | Value   |
+----+---------+
|  1 | both ab |
|  3 | only b  |
+----+---------+
2 rows in set (0.00 sec)
其中 PK 为 1 的记录在 Table_A 和 Table_B 中都有,2 为 Table_A 特有,3 为 Table_B 特有。

常用的 JOIN

1、INNER JOIN

INNER JOIN 一般被译作内连接。内连接查询能将左表(表 A)和右表(表 B)中能关联起来的数据连接后返回。文氏图:INNER JOIN示例查询:SELECT A.PK AS A_PK, B.PK AS B_PK,
       A.Value AS A_Value, B.Value AS B_Value
FROM Table_A A
INNER JOIN Table_B B
ON A.PK = B.PK;

查询结果:

+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
|    1 |    1 | both ab | both ab |
+------+------+---------+---------+
1 row in set (0.00 sec)
注:其中 A 为 Table_A 的别名,B 为 Table_B 的别名,下同。2、LEFT JOINLEFT JOIN 一般被译作左连接,也写作 LEFT OUTER JOIN。左连接查询会返回左表(表 A)中所有记录,不管右表(表 B)中有没有关联的数据。在右表中找到的关联数据列也会被一起返回。文氏图:LEFT JOIN示例查询:SELECT A.PK AS A_PK, B.PK AS B_PK,
       A.Value AS A_Value, B.Value AS B_Value
FROM Table_A A
LEFT JOIN Table_B B
ON A.PK = B.PK;

查询结果:

+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
|    1 |    1 | both ab | both ba |
|    2 | NULL | only a  | NULL    |
+------+------+---------+---------+
2 rows in set (0.00 sec)

3、RIGHT JOIN

RIGHT JOIN 一般被译作右连接,也写作 RIGHT OUTER JOIN。右连接查询会返回右表(表 B)中所有记录,不管左表(表 A)中有没有关联的数据。在左表中找到的关联数据列也会被一起返回。文氏图:RIGHT JOIN示例查询:SELECT A.PK AS A_PK, B.PK AS B_PK,
       A.Value AS A_Value, B.Value AS B_Value
FROM Table_A A
RIGHT JOIN Table_B B
ON A.PK = B.PK;

查询结果:

+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
|    1 |    1 | both ab | both ba |
| NULL |    3 | NULL    | only b  |
+------+------+---------+---------+
2 rows in set (0.00 sec)

4、FULL OUTER JOIN

FULL OUTER JOIN 一般被译作外连接、全连接,实际查询语句中可以写作 FULL OUTER JOIN 或 FULL JOIN。外连接查询能返回左右表里的所有记录,其中左右表里能关联起来的记录被连接后返回。文氏图:FULL OUTER JOIN示例查询:SELECT A.PK AS A_PK, B.PK AS B_PK,
       A.Value AS A_Value, B.Value AS B_Value
FROM Table_A A
FULL OUTER JOIN Table_B B
ON A.PK = B.PK;

查询结果:

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FULL OUTER JOIN Table_B B
ON A.PK = B.PK' at line 4
注:我当前示例使用的 MySQL 不支持 FULL OUTER JOIN。应当返回的结果(使用 UNION 模拟):mysql> SELECT *
    -> FROM Table_A
    -> LEFT JOIN Table_B
    -> ON Table_A.PK = Table_B.PK
    -> UNION ALL
    -> SELECT *
    -> FROM Table_A
    -> RIGHT JOIN Table_B
    -> ON Table_A.PK = Table_B.PK
    -> WHERE Table_A.PK IS NULL;
+------+---------+------+---------+
| PK   | Value   | PK   | Value   |
+------+---------+------+---------+
|    1 | both ab |    1 | both ba |
|    2 | only a  | NULL | NULL    |
| NULL | NULL    |    3 | only b  |
+------+---------+------+---------+
3 rows in set (0.00 sec)

小结

以上四种,就是 SQL 里常见 JOIN 的种类和概念了,看一下它们的合影:小结有没有感觉少了些什么,学数学集合时完全不止这几种情况?确实如此,继续看。

延伸用法

1、LEFT JOIN EXCLUDING INNER JOIN

返回左表有但右表没有关联数据的记录集。文氏图:LEFT JOIN EXCLUDING INNER JOIN示例查询:SELECT A.PK AS A_PK, B.PK AS B_PK,
       A.Value AS A_Value, B.Value AS B_Value
FROM Table_A A
LEFT JOIN Table_B B
ON A.PK = B.PK
WHERE B.PK IS NULL;
查询结果:+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
|    2 | NULL | only a  | NULL    |
+------+------+---------+---------+
1 row in set (0.01 sec)

2、RIGHT JOIN EXCLUDING INNER JOIN

返回右表有但左表没有关联数据的记录集。文氏图:RIGHT JOIN EXCLUDING INNER JOIN示例查询:SELECT A.PK AS A_PK, B.PK AS B_PK,
       A.Value AS A_Value, B.Value AS B_Value
FROM Table_A A
RIGHT JOIN Table_B B
ON A.PK = B.PK
WHERE A.PK IS NULL;

查询结果:

+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
| NULL |    3 | NULL    | only b  |
+------+------+---------+---------+
1 row in set (0.00 sec)

3、FULL OUTER JOIN EXCLUDING INNER JOIN

返回左表和右表里没有相互关联的记录集。文氏图:FULL OUTER JOIN EXCLUDING INNER JOIN示例查询:SELECT A.PK AS A_PK, B.PK AS B_PK,
       A.Value AS A_Value, B.Value AS B_Value
FROM Table_A A
FULL OUTER JOIN Table_B B
ON A.PK = B.PK
WHERE A.PK IS NULL
OR B.PK IS NULL;

因为使用到了 FULL OUTER JOIN,MySQL 在执行该查询时再次报错。

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FULL OUTER JOIN Table_B B
ON A.PK = B.PK
WHERE A.PK IS NULL
OR B.PK IS NULL' at line 4

应当返回的结果(用 UNION 模拟):

mysql> SELECT *
    -> FROM Table_A
    -> LEFT JOIN Table_B
    -> ON Table_A.PK = Table_B.PK
    -> WHERE Table_B.PK IS NULL
    -> UNION ALL
    -> SELECT *
    -> FROM Table_A
    -> RIGHT JOIN Table_B
    -> ON Table_A.PK = Table_B.PK
    -> WHERE Table_A.PK IS NULL;
+------+--------+------+--------+
| PK   | Value  | PK   | Value  |
+------+--------+------+--------+
|    2 | only a | NULL | NULL   |
| NULL | NULL   |    3 | only b |
+------+--------+------+--------+
2 rows in set (0.00 sec)

总结

以上七种用法基本上可以覆盖各种 JOIN 查询了。七种用法的全家福:看着它们,我仿佛回到了当年学数学,求交集并集的时代……顺带张贴一下 C.L. Moffatt 带 SQL 语句的图片,配合学习,风味更佳:

更多的 JOIN

除以上几种外,还有更多的 JOIN 用法,比如 CROSS JOIN(迪卡尔集)、SELF JOIN,可以参考 SQL JOINS Slide Presentation 学习。

1、CROSS JOIN

返回左表与右表之间符合条件的记录的迪卡尔集。图示:示例查询:SELECT A.PK AS A_PK, B.PK AS B_PK,
       A.Value AS A_Value, B.Value AS B_Value
FROM Table_A A
CROSS JOIN Table_B B;

查询结果:

+------+------+---------+---------+
| A_PK | B_PK | A_Value | B_Value |
+------+------+---------+---------+
|    1 |    1 | both ab | both ba |
|    2 |    1 | only a  | both ba |
|    1 |    3 | both ab | only b  |
|    2 |    3 | only a  | only b  |
+------+------+---------+---------+
4 rows in set (0.00 sec)
上面讲过的几种 JOIN 查询的结果都可以用 CROSS JOIN 加条件模拟出来,比如 INNER JOIN 对应 CROSS JOIN ... WHERE A.PK = B.PK。

2、SELF JOIN

返回表与自己连接后符合条件的记录,一般用在表里有一个字段是用主键作为外键的情况。比如 Table_C 的结构与数据如下:+--------+----------+-------------+
| EMP_ID | EMP_NAME | EMP_SUPV_ID |
+--------+----------+-------------+
|   1001 | Ma       |        NULL |
|   1002 | Zhuang   |        1001 |
+--------+----------+-------------+
2 rows in set (0.00 sec)
EMP_ID 字段表示员工 ID,EMP_NAME 字段表示员工姓名,EMP_SUPV_ID 表示主管 ID。示例查询:现在我们想查询所有有主管的员工及其对应的主管 ID 和姓名,就可以用 SELF JOIN 来实现。SELECT A.EMP_ID AS EMP_ID, A.EMP_NAME AS EMP_NAME,
    B.EMP_ID AS EMP_SUPV_ID, B.EMP_NAME AS EMP_SUPV_NAME
FROM Table_C A, Table_C B
WHERE A.EMP_SUPV_ID = B.EMP_ID;
查询结果:+--------+----------+-------------+---------------+
| EMP_ID | EMP_NAME | EMP_SUPV_ID | EMP_SUPV_NAME |
+--------+----------+-------------+---------------+
|   1002 | Zhuang   |        1001 | Ma            |
+--------+----------+-------------+---------------+
1 row in set (0.00 sec)

作者:码志 链接:https://mazhuang.org/2017/09/11/joins-in-sql/

推荐阅读

华为 Java 开发编程军规,谁违反谁走

厉害了,小姐姐用动图展示 10 大 Git 命令!

Linux 最常用命令整理,建议收藏!

再见,Navicat!IDEA 这个兄弟,真香!

Redis 6.0 这个新特性真牛逼!

为什么老外不愿意用 MyBatis?

IDEA 实用小技巧,Mark起来!

扫码关注小姐姐学Java

最近小姐姐在面试,整理了一份《Java面试通关手册》,覆盖了JVM、多线程、SSM、Redis、MySQL、微服务、算法、数据结构等等。获取方式:点“在看”,关注公众号回复 666 领取。

sql join on和不用join区别_图解 SQL 各种 JOIN,太有用了!相关推荐

  1. left join 临时表_图解SQL的JOIN

    对于SQL的Join,在学习起来可能是比较乱的.我们知道,SQL的Join语法有很多inner的,有outer的,有left的,有时候,对于Select出来的结果集是什么样子有点不是很清楚.Codin ...

  2. sql left join用法_图解 SQL 中 JOIN 的各种用法

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 作者:CodingStar cnblogs.com/BoyceYang/p/3145279 ...

  3. python和java还有sql区别_为什么SQL聚合函数比Python和Java(或Poor Man的OLAP)慢得多,

    Postgres做得比看起来好多了(保持数据一致性开始!) 如果值不必是100%,或者如果表很少更新,但是您经常运行此计算,则可能需要查看物化视图以加速. (注意,我没有在Postgres使用物化视图 ...

  4. sql 复合主键 联合主键_学习SQL:主键

    sql 复合主键 联合主键 If you've already worked with databases, then you could hardly miss the term – Primary ...

  5. sql中聚合函数和分组函数_学习SQL:聚合函数

    sql中聚合函数和分组函数 SQL has many cool features and aggregate functions are definitely one of these feature ...

  6. inner join on 加条件和where加条件_图解 SQL 中各种连接 JOIN

    先用文字来捋一下思路,数据库操作中无非就是「 增删查改 」,其中「 查」用得最多且最复杂,变化多端.查询的时候,我们可以只是单表查询,也可以是多表连接查询,单表查询中的学问也很大,但限于篇幅,本次主要 ...

  7. mysql版本链图解_图解 SQL 中各种连接 JOIN

    先用文字来捋一下思路,数据库操作中无非就是「增删查改」,其中「 查」用得最多且最复杂,变化多端.查询的时候,我们可以只是单表查询,也可以是多表连接查询,单表查询中的学问也很大,但限于篇幅,本次主要分享 ...

  8. sql数据库和mysql有什么区别_【数据库】MySQL和sql的区别有哪些 - 收获啦

    sql是什么? sql,全称:结构化查询语言(Structured Query Language),是一种用于操作数据库的语言,它是用于所有数据库的基本语言.虽然,不同数据库之间存在较小的语法更改,但 ...

  9. sql如何遍历几百万的表_关于SQL查询效率,100w数据,查询只要1秒

    1.关于SQL查询效率,100w数据,查询只要1秒,与您分享: 机器情况 p4: 2.4 内存: 1 G os: windows 2003 数据库: ms sql server 2000 目的: 查询 ...

最新文章

  1. R语言使用integrate函数进行函数积分计算实战
  2. 《开源者说》08期:聊聊Java那些事儿
  3. 基于托管C++的增删改查及异步回调小程序
  4. 中医药可投期刊推荐-24本-2021版
  5. flume使用telnet作为入口出现connection refused
  6. 1026 程序运行时间 (15 分)
  7. 单片机启动流程(以STM32为例)
  8. python实现希尔排序(已编程实现)
  9. Android中使用sax解析XML
  10. oracle alter和 insert,Oracle 笔记一 select insert update delete transaction create alter
  11. IOS 腾讯微博开放平台 SDK 初体验
  12. SAP中常用SE系列TCODE汇总
  13. 小米android6.01 root,小米 小米6(安卓8.0)获取Root权限服务含精简系统方案
  14. 营销自动化权威指南_任务自动化指南
  15. 低碳环保+变废为宝=马铃薯淀粉生产废水处理设备
  16. 虚拟化arm服务器,arm服务器虚拟化(armvm虚拟化搭建手机)
  17. NLP自然语言处理之情感分析分析讲解、知识构建
  18. 为什么访问亚马逊的网站卡顿?
  19. 开发购物商城app系统软件需要多少钱
  20. 沐圣moolsun:做真正的民族品牌

热门文章

  1. C++ 内存模型——虚表(vtbl)的访问
  2. java.util —— 工具类
  3. [面试]——用一行代码判断两矩形是否相交
  4. 算法直观与对模型的理解
  5. 假设检验——抽样调查的结论依赖于样本量的大小
  6. Java知识点汇总以及常见面试题
  7. python入门指南-python3.6.0入门指南(官方版).pdf
  8. python在哪里写代码-python的代码在哪编写
  9. python是什么类型的语言-为什么说 Python 是强类型语言?
  10. 深度学习笔记 | 第16讲:语音识别——一份简短的技术综述