有关JOIN的那些事儿 -- SQL

有关JOIN的那些事儿

SQL

前言

虽然跟着书本学到了一些基础的sql语法,可是一旦要运用到实践当中就会发现和自己想的完全不一样。
就在进行多表查询时,由于每个表可能具有的某些特性或者查询时会有一些要求,这使得简单的连接查询不能派上用场或者效率太低
因此,学习一下表的连接是很有必要的

概述

www.runoob.com
以上包括:
LEFT JOIN
RIGHT JOIN
INNER JOIN
OUTER JOIN
FULL OUTER JOIN
还有一种
NATURAL JOIN

详解

1 . LEFT JOIN

  • ON 子句与 WHERE 子句的不同
  • 一种更好地理解带有 WHERE … IS NULL 子句的复杂匹配条件的简单方法
ON 与 WHERE的使用(重点)

(1)ON
ON 条件(“A LEFT JOIN B ON 条件表达式”中的ON)用来决定如何从 B 表中检索数据行。
如果 B 表中没有任何一行数据匹配 ON 的条件,将会额外生成一行所有列为 NULL 的数据
(2)WHERE
在匹配阶段 WHERE 子句的条件都不会被使用。仅在匹配阶段完成以后,WHERE 子句条件才会被使用。它将从匹配阶段产生的数据中检索过滤。
(3)区别
阶段一)它们处理数据时有先后之分,运算系统先会对on的条件进行匹配,(阶段二)然后才用where的条件对匹配后的数据进行筛选
(4)例子(来自 彭博
例:
现存在两张表product_detailsproduct

mysql> SELECT * FROM product;
+----+--------+
| id | amount |
+----+--------+
|  1 |    100 |
|  2 |    200 |
|  3 |    300 |
|  4 |    400 |
+----+--------+
4 rows in set (0.00 sec)
 
mysql> SELECT * FROM product_details;
+----+--------+-------+
| id | weight | exist |
+----+--------+-------+
|  2 |     22 |     0 |
|  4 |     44 |     1 |
|  5 |     55 |     0 |
|  6 |     66 |     1 |
+----+--------+-------+
4 rows in set (0.00 sec)

对其用左外连接的方式查询id = 2 的所有信息

mysql> SELECT * FROM product LEFT JOIN product_details
       ON (product.id = product_details.id)
       AND product_details.id=2;
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  1 |    100 | NULL |   NULL |  NULL |
|  2 |    200 |    2 |     22 |     0 |
|  3 |    300 | NULL |   NULL |  NULL |
|  4 |    400 | NULL |   NULL |  NULL |
+----+--------+------+--------+-------+
4 rows in set (0.00 sec)
 
mysql> SELECT * FROM product LEFT JOIN product_details
       ON (product.id = product_details.id)
       WHERE product_details.id=2;
+----+--------+----+--------+-------+
| id | amount | id | weight | exist |
+----+--------+----+--------+-------+
|  2 |    200 |  2 |     22 |     0 |
+----+--------+----+--------+-------+
1 row in set (0.01 sec)

可以明显看出查询结果的区别

首先,两张表会被拼接起来,其中左表的数据全部保留

然后,id = 2的条件放在AND后时 - 满足product.id=product_details.id所有项都会被列出来,不过只有满足id = 2 的行才有右表的相关信息

而将id = 2的条件放在WHERE后时 - 直接对表进行连接
如下:
阶段一:符合条件的都列出所有信息

mysql> SELECT * FROM product LEFT JOIN product_details
    ->          ON (product.id = product_details.id);
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  1 |    100 | NULL |   NULL |  NULL |
|  2 |    200 |    2 |     22 |     0 |
|  3 |    300 | NULL |   NULL |  NULL |
|  4 |    400 |    4 |     44 |     1 |
+----+--------+------+--------+-------+
4 rows in set (0.01 sec)

阶段二:对上表进行筛选 id = 2
得到

+----+--------+----+--------+-------+
| id | amount | id | weight | exist |
+----+--------+----+--------+-------+
|  2 |    200 |  2 |     22 |     0 |
+----+--------+----+--------+-------+

这就是上面结果的由来

WHERE … IS NULL 与 LEFT JOIN

如果ON语句中使用多个筛选条件并与 where…is null配合使用时会出现问题

例子

筛选条件为
(a.id=b.id) AND (b.weight!=44) AND (b.exist=0)

无*WHERE b.id IS NULL*条件时
mysql> select * from product a left join product_details b
    -> on a.id=b.id and b.weight != 44 and b.exist=0;
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  1 |    100 | NULL |   NULL |  NULL |
|  2 |    200 |    2 |     22 |     0 |
|  3 |    300 | NULL |   NULL |  NULL |
|  4 |    400 | NULL |   NULL |  NULL |
+----+--------+------+--------+-------+
4 rows in set (0.00 sec)


mysql> SELECT * FROM product a LEFT JOIN product_details b  
       ON a.id=b.id AND b.weight!=44 AND b.exist=0  
       WHERE b.id IS NULL;  
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  1 |    100 | NULL |   NULL |  NULL |
|  3 |    300 | NULL |   NULL |  NULL |
|  4 |    400 | NULL |   NULL |  NULL |
+----+--------+------+--------+-------+
3 rows in set (0.00 sec)  

对比原表product_detailsproduct会发现ON后面*(b.weight!=44) AND (b.exist=0)*的条件并没有使用

这是因为其判断机制和C语言类似,与C语言中的逻辑 AND 和 逻辑 OR表达式一样,其操作数是从左到右求值的。如果第一个参数做够判断操作结果,那么第二个参数便不会被计算求值(短路效果)

因此就出现了一些变式,其查询结果在某些时候会是一样

SELECT a.* FROM product a LEFT JOIN product_details b
ON a.id=b.id
WHERE b.id is null OR b.weight=44 OR b.exist=0;

SELECT a.* FROM product a LEFT JOIN product_details b
ON a.id=b.id AND b.weight!=44 AND b.exist!=0
WHERE b.id IS NULL;

注:结果会并不完全一样,参考以上ON 与 WHERE的使用

2 . RIGHT JOIN

总结来讲与 LEFT JOIN一样,只是一个保留了左边的所有数据,一个保留了右边的所有数据
以上案例结果如下

mysql> SELECT * FROM product right JOIN product_details
    ->        ON (product.id = product_details.id);
+------+--------+----+--------+-------+
| id   | amount | id | weight | exist |
+------+--------+----+--------+-------+
|    2 |    200 |  2 |     22 |     0 |
|    4 |    400 |  4 |     44 |     1 |
| NULL |   NULL |  5 |     55 |     0 |
| NULL |   NULL |  6 |     66 |     1 |
+------+--------+----+--------+-------+
4 rows in set (0.00 sec)

mysql> SELECT * FROM product right JOIN product_details
    ->        ON (product.id = product_details.id)
    ->        AND product_details.id=2;
+------+--------+----+--------+-------+
| id   | amount | id | weight | exist |
+------+--------+----+--------+-------+
|    2 |    200 |  2 |     22 |     0 |
| NULL |   NULL |  4 |     44 |     1 |
| NULL |   NULL |  5 |     55 |     0 |
| NULL |   NULL |  6 |     66 |     1 |
+------+--------+----+--------+-------+
4 rows in set (0.00 sec)
与上面的结果对比可以看到,多一个and条件会多进行一次筛选,不满足条件的部分置为null

mysql> SELECT * FROM product right JOIN product_details
    ->        ON (product.id = product_details.id)
    ->        WHERE product_details.id=2;
+------+--------+----+--------+-------+
| id   | amount | id | weight | exist |
+------+--------+----+--------+-------+
|    2 |    200 |  2 |     22 |     0 |
+------+--------+----+--------+-------+
1 row in set (0.00 sec)

3 . INNER JOIN

emmm,其实看完上面的LEFT JOINRIGHT JOIN以后,就会发现其他的几种都非常简单了

还是拿上文的案例来说
inner join可以理解为在左右两张表中都查找满足ON后的条件
(product.id = product_details.id)
的部分然后将其拼接起来

简单来说就是取交集

左表:
+------+--------+----+
| id   | amount | id |
+------+--------+----+
|    2 |    200 |  2 |
+------+--------+----+
右表:
+----+--------+-------+
| id | weight | exist |
+----+--------+-------+
|  2 |     22 |     0 |
+----+--------+-------+
然后连接
+------+--------+----+--------+-------+
| id   | amount | id | weight | exist |
+------+--------+----+--------+-------+
|    2 |    200 |  2 |     22 |     0 |
+------+--------+----+--------+-------+

OVER!

4 .FULL (OUTER) JOIN

从概述的图中可以看出full join其实就是取并集
而在实际运用中是比较少的(参照一下普通的连接)

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 join...'

本来想测试一下full join的效果,可是MySQL 5.5 好像不支持
因此可以参考的是另外一种变式
就是左连接并上右连接

SELECT * FROM product left JOIN product_details ON (product.id = product_details.id)
unoin all
SELECT * FROM product right JOIN product_details ON (product.id = product_details.id)

最后的结果就是上面的左连接与右连接的并
关于UNION ALL 请自行参考资料

最后

至此:有关JOIN的一些基础用法就差不多结束了,有兴趣的可以刷一些数据库的编程题,能在实际中运用才是真正学到了

查找当前薪水详情以及部门编号dept_no

查找所有已经分配部门的员工的last_name和first_name以及dept_no

查找所有员工的last_name和first_name以及对应部门编号dept_no

查找所有员工入职时候的薪水情况

网络上的资源很多,修行看个人

共勉!

参考资料
1 . LEFTJOIN
2 . 菜鸟教程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值