由微信推送引发的SQL join语句总结,顺便复习一下下MySQL

早上一起床就刷微信(真想拍死自己),看到一篇很有意思的推送,名为《图解SQL join语句》,讲的是用Venn图图解SQL join语句。看的过程中有点疑惑,干脆就用MySQL实践一下,顺带复习下MySQL嘛。这一实践下来,还发现了另外的有趣的问题,比如MySQL中并没有full outer join, 那要怎么在MySQL中模拟full outer join的问题。这么一来二去,涉及的内容就更加有意思了,不记下来有点可惜,另外国庆实在是一个放松的好时机啊,又想偷懒了,那就写博客来防止自己偷懒吧!

由于写出排版美观的博客比较费时间,所以这一系列的博客可能比较潦草,希望各位看官海涵。


为了防止遗漏,先直接上各种连接对应的Venn图,图片引自推送,原作者已不可考。另外,自然连接是无法用Venn图表示的。

由微信推送引发的SQL join语句总结,顺便复习一下下MySQL_第1张图片



假设有两个表,A表,B表,表结构与数据如下:

由微信推送引发的SQL join语句总结,顺便复习一下下MySQL_第2张图片          由微信推送引发的SQL join语句总结,顺便复习一下下MySQL_第3张图片

复习MySQL:

进入MySQL的命令:      mysql -u root -p 接着输入密码
查看数据库:           show databases; 注意复数,有分号
查看数据库表:         show tables;   注意复数,有分号
创建表:               create table A(id int, name varchar(32));
插入数据:              insert into A values(1, 'Pirate'); 注意字符串加单引号,另外如果只是插入部分字段,只需在表名后打括号,指定字段名,字段名无需加单引号


内连接 inner join:只生成匹配连接条件的记录,最常见没啥好讲。对应Venn图的求交。

由微信推送引发的SQL join语句总结,顺便复习一下下MySQL_第4张图片



全外连接 full outer join: 会生产表A与表B的记录全集,包含两边都匹配的记录(inner join的结果集),另外如果有一边没有匹配,缺失的一边为null。然而,请注意,全外连接与产生笛卡尔积结果集的自然连接是不同的!全外连接可以理解为left join与right join的并集。对应Venn图求并。



由于MySQL中没有提供full outer join关键字,我们需要用left join 与right join 再结合 union来模拟full outer join,用union当然是因为union会去重。

由微信推送引发的SQL join语句总结,顺便复习一下下MySQL_第5张图片

注意一定是A left join B union  A right join B, 这样union 的结果才会是真正的模拟到full outer join。(而不是A left join B  union  B left join A,即两次查询表的顺序要相同,因为union在去重的时候,只是单纯的看每一行是否完全相同, 1 Pirate 2 Pirate 与 2 Pirate 1Pirate会被视为不同的记录(废话),尽管我们人脑一看就知道这是一条重复的记录)


左连接 left join:生成左表的全部记录,对于右表中没有匹配的记录,用null补。对应Venn图就是左集合。

由微信推送引发的SQL join语句总结,顺便复习一下下MySQL_第6张图片

左连接 right join:生成右表的全部记录,对于左表中没有匹配的记录,用null补。对应Venn图就是右集合。

由微信推送引发的SQL join语句总结,顺便复习一下下MySQL_第7张图片


比较有趣并引起我的疑惑的是一开始给出的图中,关于下面这张图的SQL的写法,让我发现了自己一直以来在SQL语句执行顺序中的一个误区。

由微信推送引发的SQL join语句总结,顺便复习一下下MySQL_第8张图片

推送的说法是“为了生成只在表A里而不在表B中的记录,我们同样使用left join, 再用where B.id is null 来排除A与B的交集 ”。一直以来我以为where B.id is null是作用在from B的集上的,事实证明我是错的。 在join后面的where是作用在join on筛选后的结果集上的。

这里附上SQL语句的执行顺序,明确SQL语句的执行顺序很重要。

(8)SELECT (9)DISTINCT (11)<Top Num> <select list>
(1)FROM [left_table]
(3)<join_type> JOIN <right_table>
(2)ON <join_condition>
(4)WHERE <where_condition>
(5)GROUP BY <group_by_list>
(6)WITH <CUBE | RollUP>
(7)HAVING <having_condition>
(10)ORDER BY <order_by_list>

逻辑查询处理阶段简介
FROM:对FROM子句中的前两个表执行笛卡尔积(Cartesian product)(交叉联接),生成虚拟表VT1
ON:对VT1应用ON筛选器。只有那些使<join_condition>为真的行才被插入VT2。
OUTER(JOIN):如 果指定了OUTER JOIN(相对于CROSS JOIN 或(INNER JOIN),保留表(preserved table:左外部联接把左表标记为保留表,右外部联接把右表标记为保留表,完全外部联接把两个表都标记为保留表)中未找到匹配的行将作为外部行添加到 VT2,生成VT3.如果FROM子句包含两个以上的表,则对上一个联接生成的结果表和下一个表重复执行步骤1到步骤3,直到处理完所有的表为止。
WHERE:对VT3应用WHERE筛选器。只有使<where_condition>为true的行才被插入VT4.
GROUP BY:按GROUP BY子句中的列列表对VT4中的行分组,生成VT5.
CUBE|ROLLUP:把超组(Suppergroups)插入VT5,生成VT6.
HAVING:对VT6应用HAVING筛选器。只有使<having_condition>为true的组才会被插入VT7.
SELECT:处理SELECT列表,产生VT8.
DISTINCT:将重复的行从VT8中移除,产生VT9.
ORDER BY:将VT9中的行按ORDER BY 子句中的列列表排序,生成游标(VC10).
TOP:从VC10的开始处选择指定数量或比例的行,生成表VT11,并返回调用者。



你可能感兴趣的:(JOIN,sql,mysql,venn)