[sql] view plain copy
SELECT[DISTINCT]
FROM
WHERE
GROUP BY
HAVING
UNION
ORDER BY
为了方便理解,上面并没有把所有的 SQL 语法结构都列出来,但是已经足以说明 SQL 语句的语法顺序和其
执行顺序完全不一样,就以上述语句为例,其执行顺序为:
[sql] view plain copy
FROM
WHERE
GROUP BY
HAVING
SELECT
DISTINCT
UNION
ORDER BY
关于 SQL 语句的执行顺序,有三个值得我们注意的地方:
1、 FROM 才是 SQL 语句执行的第一步,并非 SELECT 。数据库在执行 SQL 语句的第一步是将数据从硬盘
加载到数据缓冲区中,以便对这些数据进行操作。(译者注:原文为“The first thing that happens is loadin
g data from the disk into memory, in order to operate on such data.”,但是并非如此,以 Oracle 等常用数
据库为例,数据是从硬盘中抽取到数据缓冲区中进行操作。)
2、 SELECT 是在大部分语句执行了之后才执行的,严格的说是在 FROM 和 GROUP BY 之后执行的。理解
这一点是非常重要的,这就是你不能在 WHERE 中使用在 SELECT 中设定别名的字段作为判断条件的原因。
[sql] view plain copy
SELECT A.x + A.y AS z
FROM A
WHERE z = 10 -- z 在此处不可用,因为SELECT是最后执行的语句
如果你想重用别名z,你有两个选择。要么就重新写一遍 z 所代表的表达式:
[sql] view plain copy
SELECT A.x + A.y AS z
FROM A
WHERE (A.x + A.y) = 10
…或者求助于衍生表、通用数据表达式或者视图,以避免别名重用。请看下文中的例子。
3、 无论在语法上还是在执行顺序上, UNION 总是排在在 ORDER BY 之前。很多人认为每个 UNION 段都
能使用 ORDER BY 排序,但是根据 SQL 语言标准和各个数据库 SQL 的执行差异来看,这并不是真的。尽
管某些数据库允许 SQL 语句对子查询(subqueries)或者派生表(derived tables)进行排序,但是这并不
说明这个排序在 UNION 操作过后仍保持排序后的顺序。
[sql] view plain copy
INNER JOIN(或者是 JOIN )
OUTER JOIN(包括: LEFT 、 RIGHT、 FULL OUTER JOIN)
用例子最容易说明其中区别:
[sql] view plain copy
-- 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
作者: 感悟时分 时间: 2018-4-12 16:26
-- 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] view plain copy
-- 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] view plain copy
-- A derived table
FROM (SELECT * FROM author)
需要注意的是有些时候我们可以给派生表定义一个相关名(即我们所说的别名)。
[sql] view plain copy
-- A derived table with an alias
FROM (SELECT * FROM author) a
派生表可以有效的避免由于 SQL 逻辑而产生的问题。举例来说:如果你想重用一个用 SELECT 和 WHERE
语句查询出的结果,这样写就可以(以 Oracle 为例):
[sql] view plain copy
-- Get authors' first and last names, and their age in days
SELECT first_name, last_name, age
FROM (
SELECT first_name, last_name, current_date - date_of_birth age
FROM author
)
-- If the age is greater than 10000 days
WHERE age > 10000
需要我们注意的是:在有些数据库,以及 SQL : 1990 标准中,派生表被归为下一级——通用表语句( comm
on table experssion)。这就允许你在一个 SELECT 语句中对派生表多次重用。上面的例子就(几乎)等价于
下面的语句:
[sql] view plain copy
WITH a AS (
SELECT first_name, last_name, current_date - date_of_birth age
FROM author
)
SELECT *
FROM a
WHERE age > 10000
当然了,你也可以给“ a ”创建一个单独的视图,这样你就可以在更广泛的范围内重用这个派生表了。
[java] view plain copy
FROM a, b
现在,我们将 GROUP BY 应用到上面的语句中:
[sql] view plain copy
GROUP BY A.x, A.y, B.z
上面语句的结果就是产生出了一个包含三个字段的新的表的引用。我们来仔细理解一下这句话:当你应用 GRO
UP BY 的时候, SELECT 后没有使用聚合函数的列,都要出现在 GROUP BY 后面。(译者注:原文大意为“当你是
用 GROUP BY 的时候,你能够对其进行下一级逻辑操作的列会减少,包括在 SELECT 中的列”)。
[sql] view plain copy
需要注意的是:其他字段能够使用聚合函数:
SELECT A.x, A.y, SUM(A.z)
FROM A
GROUP BY A.x, A.y
还有一点值得留意的是: MySQL 并不坚持这个标准,这的确是令人很困惑的地方。(译者注:这并不是说 MyS
QL 没有 GROUP BY 的功能)但是不要被 MySQL 所迷惑。 GROUP BY 改变了对表引用的方式。你可以像这样既在
SELECT 中引用某一字段,也在 GROUP BY 中对其进行分组
我们学到了什么?
一些更复杂的规则多到足够写出另一篇文章了。比如:为何你不能在一个没有 GROUP BY 的 SELECT 语句中同
时使用普通函数和聚合函数?(上面的第 4 条)
原因如下:
凭直觉,这种做法从逻辑上就讲不通。
如果直觉不能够说服你,那么语法肯定能。 SQL : 1999 标准引入了 GROUPING SETS,SQL: 2003 标准引入
了 group sets : GROUP BY() 。无论什么时候,只要你的语句中出现了聚合函数,而且并没有明确的 GROUP BY
语句,这时一个不明确的、空的 GROUPING SET 就会被应用到这段 SQL 中。因此,原始的逻辑顺序的规则就
被打破了,映射(即 SELECT )关系首先会影响到逻辑关系,其次就是语法关系。(译者注:这段话原文就比
较艰涩,可以简单理解如下:在既有聚合函数又有普通函数的 SQL 语句中,如果没有 GROUP BY 进行分组,S
QL 语句默认视整张表为一个分组,当聚合函数对某一字段进行聚合统计的时候,引用的表中的每一条 record
就失去了意义,全部的数据都聚合为一个统计值,你此时对每一条 record 使用其它函数是没有意义的)。