当我们在试图理解SQL
中的join
用法时,获得大量的信息都是韦恩图(Venn Diagram)示例。然而,韦恩图真的能准确的说明join
的用法吗?不然!
实际上,韦恩图只适合以下三种的SQL
操作:
我们可以用这样的韦恩图来表示它们:
UNION(并集)
INTERSECT(交集)
EXCEPT(补集)
关键的问题在于:韦恩图的操作基于的集合都是同种类型的。例如图中示例,所有的记录都是由first name
和last name
组成,如果不是由同种类型的记录组成的集合,则INTERSECT
和EXCEPT
操作就变的没有什么意义了。那么,如果我想将演员表和对应的电影表关联起来,用韦恩图这种方法显然就不可能了。
于是,SQL
中出现了join
,可以用来关联不同类型的数据。那么join
的实质是什么呢?
join
说白了是:带有filter
的笛卡尔积(cartesian produce),用图说明:
我们使用什么样的方法来形象化join
操作呢?
首先我们来看看cross join
吧,cross join
是一种笛卡尔积的形式,任何类型的join
都可以从cross join
中推到出来。
需要注意的是:cross join
也可以写成用逗号隔开表的形式,它做的事情仅仅是将左边的每一条记录和右边的每一条记录组合起来。如果左边是3条记录,右边是4条记录,那么组合及时3x4=12
条记录。
所有的join都是基于cross join,再辅助与一定的filter,有的时候还要加上UNION操作。
INNER JOIN
INNER JOIN
是cross join
结果集中再指定一个过滤条件,看一个SQL示例:
-- "Classic" ANSI JOIN syntax
SELECT *
FROM author a
JOIN book b ON a.author_id = b.author_id
-- "Nice" ANSI JOIN syntax
SELECT *
FROM author a
JOIN book b USING (author_id)
-- "Old" syntax using a "CROSS JOIN"
SELECT *
FROM author a, book b
WHERE a.author_id = b.author_id
OUTER JOIN
OUTER JOIN
可以让你在没有满足指定过滤条件时,仍然保留左边或者右边或者两边的记录。
用LEFT JOIN
做一个SQL示例:
SELECT *
FROM author a
LEFT JOIN book b USING (author_id)
这个SQL将作者和著作用笛卡尔积的方式先组合起来,然后过滤出来有相同的author_id的记录,并且如果作者没有相应的著作,仍然保留作者的记录,著作的记录用NULL
表示。
用基本的SQL来表示上述的LEFT JOIN
操作:
SELECT *
FROM author a
JOIN book b USING (author_id)
UNION
SELECT a.*, NULL, NULL, NULL, ..., NULL
FROM (
SELECT a.*
FROM author a
EXCEPT
SELECT a.*
FROM author a
JOIN book b USING (author_id)
) a
当你再向你小伙伴解释
join
操作时,就不要再用不确切的韦恩图方式了。