整理自网络,我也忘了从哪个网站了。
一、SQL是一种声明式语言
首先要把这个概念记在脑中:“声明”。 SQL 语言是为计算机声明了一个你想从原始数据中获得什么样的结果的一个范例,而不是告诉计算机如何能够得到结果。
简单地说,SQL 语言声明的是结果集的属性,计算机会根据 SQL 所声明的内容来从数据库中挑选出符合声明的数据。
二、SQL的语法并不按照语法顺序执行
SQL 语句有一个让大部分人都感到困惑的特性,就是:SQL 语句的执行顺序跟其语句的语法顺序并不一致。SQL 语句的执行顺序是:
<ol>
<li>FROM
</li>
<li>WHERE
</li>
<li>GROUP BY
</li>
<li>HAVING
</li>
<li>SELECT
</li>
<li>DISTINCT
</li>
<li>UNION
</li>
<li>ORDER BY
</li>
</ol>
关于 SQL 语句的执行顺序,有两个值得我们注意的地方:
-
FROM才是SQL语句执行的第一步,并非 SELECT 。数据库在执行 SQL 语句的第一步是将数据从硬盘加载到数据缓冲区中,以便对这些数据进行操作。但是并非如此,以 Oracle 等常用数据库为例,数据是从硬盘中抽取到数据缓冲区中进行操作。
-
SELECT 是在大部分语句执行了之后才执行的,理解这一点是非常重要的,这就是你不能在 WHERE 中使用在 SELECT 中设定别名的字段作为判断条件的原因。
SELECT A.x + A.y AS z
FROM A
WHERE z = 10 // z在此处不可用,因为SELECT是最后执行的语句
永远要记得: SQL 语句的语法顺序和其执行顺序并不一致,这样我们就能避免一般性的错误。
三、SQL语言的核心是对表的引用
FROM 语句的“输出”是一张联合表,来自于所有引用的表在某一维度上的联合。
FROM a, b
上面这句 FROM 语句的输出是一张联合表,联合了表 a 和表 b 。如果 a 表有三个字段, b 表有 5 个字段,那么这个“输出表”就有 8 个字段。
四、SQL语句中推荐使用表连接
我们先看看刚刚这句话:
FROM a, b
高级SQL程序员也许会给你忠告:尽量不要使用逗号来代替JOIN
进行表的连接,这样会提高你的 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...
要使用:
FROM a
JOIN b
ON a.id = b.id
五、SQL语句中不同的连接操作
SQL 语句中,表连接的方式从根本上分为五种:
• EQUI JOIN(等值连接)
• SEMI JOIN(半连接)
• ANTI JOIN(反连接)
• CROSS JOIN(交叉连接)
• DIVISION
5.1 EQUI JOIN(等值连接)
这是一种最普通的 JOIN 操作,它包含两种连接方式:
- INNER JOIN(或者是 JOIN )内连接
- OUTER JOIN(包括: LEFT 、 RIGHT、 FULL OUTER JOIN)外连接
5.2 SEMI JOIN(半连接)
这种连接关系在 SQL 中有两种表现方式:使用IN
,或者使用EXISTS
。“ SEMI ”在拉丁文中是“半”的意思。这种连接方式是只连接目标表的一部分。
FROM author
WHERE author.id IN (SELECT book.author_id FROM book)
或者
FROM author
WHERE EXISTS (SELECT * FROM book WHERE book.author_id = author.id)
尽管没有严格的规定说明你何时应该使用 IN ,何时应该使用 EXISTS ,但是这些事情你还是应该知道的:
• IN比 EXISTS 的可读性更好
• EXISTS 比IN 的表达性更好(更适合复杂的语句)
• 二者之间性能没有差异(但对于某些数据库来说性能差异会非常大)
因为使用 INNER JOIN 也能得到书名表中书所对应的作者信息,所以很多初学者机会认为可以通过 DISTINCT 进行去重,然后将 SEMI JOIN 语句写成这样:
SELECT DISTINCT first_name, last_name
FROM author
JOIN book ON author.id = book.author_id
这是一种很糟糕的写法,原因如下:
• SQL 语句性能低下:因为去重操作( DISTINCT )需要数据库重复从硬盘中读取数据到内存中。
• 这么写并非完全正确:尽管也许现在这么写不会出现问题,但是随着 SQL 语句变得越来越复杂,你想要去重得到正确的结果就变得十分困难。
5.3 ANTI JOIN(反连接)
这种连接的关系跟 SEMI JOIN 刚好相反。在 IN 或者 EXISTS 前加一个 NOT 关键字就能使用这种连接。举个例子来说,我们列出书名表里没有书的作者:
FROM author
WHERE author.id
NOT IN (SELECT book.author_id FROM book)
或者
FROM author
WHERE NOT EXISTS (SELECT 1 FROM book WHERE book.author_id = author.id)
5.4 CROSS JOIN(交叉连接)
这个连接过程就是两个连接的表的乘积:即将第一张表的每一条数据分别对应第二张表的每条数据。我们之前见过,这就是逗号在 FROM 语句中的用法。
六、SQL中如同变量的派生表
在这之前,我们学习到过 SQL 是一种声明性的语言,并且 SQL 语句中不能包含变量。但是你能写出类似于变量的语句,这些就叫做派生表。说白了,所谓的派生表就是在括号之中的子查询。
FROM (SELECT * FROM author)
需要注意的是有些时候我们可以给派生表定义一个相关名(即我们所说的别名)。
FROM (SELECT * FROM author) a
七、SQL语句中 GROUP BY 是对表的引用进行的操作
让我们再回想一下之前的 FROM 语句:
FROM a, b
现在,我们将 GROUP BY 应用到上面的语句中:
GROUP BY A.x, A.y, B.z
上面语句的结果就是产生出了一个包含三个字段的新的表的引用。我们来仔细理解一下这句话:当你是用 GROUP BY 的时候,你能够对其进行下一级逻辑操作的列会减少,包括在 SELECT 中的列。没有使用聚合函数又不是GROUP BY的字段如果出现在SELECT后会报错。
需要注意的是其他字段能够使用聚合函数:
SELECT A.x, A.y, SUM(A.z)
FROM A
GROUP BY A.x, A.y
八、SQL 语句中的 SELECT 实质上是对关系的映射
一旦你建立起来了表的引用,经过修改、变形,你能够一步一步的将其映射到另一个模型中。 SELECT 语句就像一个“投影仪”,我们可以将其理解成一个将源表中的数据按照一定的逻辑转换成目标表数据的函数。
SELECT 语句可能是 SQL 语句中最难的部分了,尽管他看上去很简单。其他语句的作用其实就是对表的不同形式的引用。而 SELECT 语句则把这些引用整合在了一起,通过逻辑规则将源表映射到目标表,而且这个过程是可逆的,我们可以清楚的知道目标表的数据是怎么来的。
想要学习好 SQL 语言,就要在使用 SELECT 语句之前弄懂其他的语句,虽然 SELECT 是语法结构中的第一个关键词,但它应该是我们最后一个掌握的。
九、SQL 语句中的几个简单的关键词: DISTINCT , UNION , ORDER BY 和 OFFSET
- 集合运算( DISTINCT 和 UNION )
- 排序运算( ORDER BY,OFFSET…FETCH)
集合运算主要操作在于集合上,事实上指的就是对表的一种操作。从概念上来说,他们很好理解:
- DISTINCT 在映射之后对数据进行去重
- UNION 将两个子查询拼接起来并去重
- UNION ALL 将两个子查询拼接起来但不去重
- EXCEPT 将第二个字查询中的结果从第一个子查询中去掉
- INTERSECT 保留两个子查询中都有的结果并去重
排序运算跟逻辑关系无关。这是一个 SQL 特有的功能。排序运算不仅在 SQL 语句的最后,而且在 SQL 语句运行的过程中也是最后执行的。使用 ORDER BY 和 OFFSET…FETCH 是保证数据能够按照顺序排列的最有效的方式。
OFFSET…SET是一个没有统一确定语法的语句,不同的数据库有不同的表达方式,如 MySQL 和 PostgreSQL 的 LIMIT…OFFSET、SQL Server 和 Sybase 的 TOP…START AT 等。
正如其他语言一样,想要学好 SQL 语言就要大量的练习。
网友评论