4. 灵活引用表能使 SQL 语句变得更强大
灵活引用表能使 SQL 语句变得更强大。一个简单的例子就是 JOIN 的使用。
严格的说 JOIN 语句并非是 SELECT 中的一部分,而是一种特殊的表引用语句。
SQL 语言标准中表的连接定义如下:
<table reference> ::= <table name> | <derived table> | <joined table>
就拿之前的例子来说:
FROM a, b
a 可能输如下表的连接:
a1 JOIN a2 ON a1.id = a2.id
将它放到之前的例子中就变成了:
尽管将一个连接表用逗号跟另一张表联合在一起并不是常用作法,但是你的确可以这么做。结果就是,最终输出的表就有了 a1+a2+b 个字段了。
在 SQL 语句中派生表的应用甚至比表连接更加强大,下面我们就要讲到表连接。
我们学到了什么?
思考问题时,要从表引用的角度出发,这样就很容易理解数据是怎样被 SQL 语句处理的,并且能够帮助你理解那些复杂的表引用是做什么的。
更重要的是,要理解 JOIN 是构建连接表的关键词,并不是 SELECT 语句的一部分。有一些数据库允许在 INSERT 、 UPDATE 、 DELETE 中使用 JOIN 。
5. SQL 语句中推荐使用表连接
我们先看看刚刚这句话:
FROM a, b
高级 SQL 程序员也许给你忠告:尽量不要使用逗号来代替 JOIN 进行表的连接,这样会提高你的 SQL 语句的可读性,并且可以避免一些错误。利用逗号来简化 SQL 语句有时候会造成思维上的混乱,想一下下面的语句:
FROM a, b, c, d, e, f, g, h WHERE a.a1 = b.bx AND a.a2 = c.c1 AND d.d1 = b.bc -- etc...
我们不难看出使用 JOIN 语句的好处在于:安全。JOIN 和要连接的表离得非常近,这样就能避免错误。
更多连接的方式,JOIN 语句能去区分出来外连接和内连接等。
我们学到了什么?
记着要尽量使用 JOIN 进行表的连接,永远不要在 FROM 后面使用逗号连接表。
6. SQL 语句中不同的连接操作
SQL 语句中,表连接的方式从根本上分为五种:
EQUI JOIN SEMI JOIN ANTI JOIN CROSS JOIN DIVISION
EQUI JOIN 是一种最普通的 JOIN 操作,它包含两种连接方式:
INNER JOIN(或者是 JOIN )
OUTER JOIN(包括:LEFT 、 RIGHT、 FULL OUTER JOIN)
用例子最容易说明其中区别:
-- This table reference contains authors and their books. -- There is one record for each book and its author. -- authors without books are NOT included author JOIN book ON author.id = book.author_id -- This table reference contains authors and their books -- There is one record for each book and its author. -- ... OR there is an "empty" record for authors without books-- ("empty" meaning that all book columns are NULL) author LEFT OUTER JOIN book ON author.id = book.author_id SEMI JOIN
这种连接关系在 SQL 中有两种表现方式:使用 IN,或者使用 EXISTS。“ SEMI ”在拉丁文中是“半”的意思。这种连接方式是只连接目标表的一部分。这是什么意思呢?
再想一下上面关于作者和书名的连接。我们想象一下这样的情况:我们不需要作者 / 书名这样的组合,只是需要那些在书名表中的书的作者信息。那我们就能这么写:
-- Using IN FROM author WHERE author.id IN(SELECT book.author_id FROM book) -- Using EXISTS FROM author WHERE EXISTS (SELECT 1 FROM book WHERE book.author_id = author.id)
尽管没有严格的规定说明你何时应该使用 IN ,何时应该使用 EXISTS ,但是这些事情你还是应该知道的:
IN比 EXISTS 的可读性更好
EXISTS 比IN 的表达性更好(更适合复杂的语句)
二者之间性能没有差异(但对于某些数据库来说性能差异会非常大) 因为使用 INNER JOIN 也能得到书名表中书所对应的作者信息,所以很多初学者机会认为可以通过 DISTINCT 进行去重,然后将 SEMI JOIN 语句写成这样:
-- Find only those authors who also have books SELECT DISTINCT first_name, last_name FROM author JOIN book ON author.id = book.author_id
这是一种很糟糕的写法,原因如下:
- SQL 语句性能低下:因为去重操作( DISTINCT )需要数据库重复从硬盘中读取数据到内存中。
- 这么写并非完全正确:尽管也许现在这么写不会出现问题,但是随着 SQL 语句变得越来越复杂,你想要去重得到正确的结果就变得十分困难。