简介
很多程序员视SQL如猛兽.它是为数不多的声明式语言的一种,它的表现形式与一些面向对象语言或者函数式语言完全不同.
这篇文章主要会关注 SELECT语句.
SQL is declarative(SQL是声明性的)
把这个概念放在脑子里,声明性.唯一的一个范例就是,你只是以”声明”的性质来获取你想要的结果.而不是你的电脑如何计算出这些结果.
SELECT first_name, last_name
FROM employees
WHERE salary > 100000
这很容易理解,你并不关系员工的档案是从哪来的.你仅仅想要拿到那些在薪水范围内的员工信息.
总结:
问题在于我们通常认为这是在进行命令式的编程.比如: “机器,做这个,然后做那个,但是开始之前,先做一个检查,如果怎样怎样就失败”.这些包含了,在变量中保存缓存结果,编写循环,迭代,调用函数等等.
丢掉这些想法,然后思考如何使用声明的方式.而不是告诉机器如何去计算.
SQL syntax is not “well-ordered”(SQL的语法并不是井然有序的)
一个普遍困惑的来源就是,SQL中的语法元素顺序完全不同于其执行顺序.
词汇的排序方式如下:
- SELECT [ DISTINCT ]
- FROM
- WHERE
- GROUP BY
- HAVING
- UNION
- ORDER BY
为了简单,并没有列出所有的SQL子句.这些词汇顺序跟逻辑顺序有很大的不同(或者跟执行的顺序相反,取决于有效的选择):
- FROM
- WHERE
- GROUP BY
- HAVING
- SELECT
- DISTINCT
- UNION
- ORDER BY
有三点需要注意的地方:
FROM 作为了第一个子句,而不是 SELECT.发生的第一件事就是将数据从磁盘加载到内存,以便于对这些数据进行操作.
SELECT 是在多个子句之后才执行.重要的是,在FROM 和 GROUP之后.这对于理解为什么你能在SELECT子句引用WHERE子句中的声明非常重要.
比如,下面是不可行的:
SELECT A.x + A.y AS z FROM A WHERE z = 10 -- z is not available here!
如果你想重用z,有两种方式,重复该表达式:
SELECT A.x + A.y AS z FROM A WHERE (A.x + A.y) = 10
UNION在两种顺序中都处于 ORDER BY之前,很多人都会人会多个UNION子查询都会被排序,但是根据SQL标准和很多SQL方言,并不是这样.虽然一些方言支持子查询或者导出表有排序,但是在UNION操作之后的排序并不能做出保证.
注意,并不是所有的数据库实现都是一样的.比如上面的第二条,在MySQL,PostgreSQL,SQLite中并没有准确应用.
总结:
牢记字典顺序和逻辑顺序以避免基本错误.如果你理解其中的区别,类似 “为什么有些可以执行”而”有些不可以”这样的问题就会变得显而易见.
SQL is about table references(SQL是关于表的引用)
由于词汇顺序与逻辑顺序的不同,很多新手会误以为SQL中字段值是一等公民.他们并不是,最重要的是表引用.
在SQL标准中FROM的从句的定义如下:
<from clause> ::=
FROM <table reference>
[ { <comma> <table reference> }... ]
The “output” of the FROM clause is a combined table reference of the combined degree of all table references.
FROM a, b
该从句产生一个组合表引用,a + b,如果a有三列,b有5列,这时,输出的表将会含有8(3+5)个列.
同时如果a有3行,b有5行,总共将会有15(3x5)行.
总结:
总是认为SQL是表的引用以理解数据是如何被SQL从句传输的.
SQL table references can be rather powerful(SQL表引用的强大之处)
表引用的强大之处在JOIN关键字上体现的比较明显,JOIN并不是SELECT语句的一部分.但是属于特殊的表引用的一部分.连接后的表在SQL标准中的定义:
<table reference> ::=
<table name>
| <derived table>
| <joined table>
仍然是上面的例子:
FROM a, b
按下面的方式进行连接:
a1 JOIN a2 ON a1.id = a2.id
然后两个语句结合在一起:
FROM a1 JOIN a2 ON a1.id = a2.id, b
结果将会得到一个a1+a2+b的连接.
总结:
仍然总是任务SQL是表的引用,以便于理解复杂的表引用的构成.
SQL JOIN tables should be used rather than comma-separated tables(总是使用连接表而不是逗号分割的表)
首先看下面的从句:
FROM a, b
有经验的SQL开发人员总是会告诉你不要使用逗号分割的表组合方式,而是尽量使用JOIN来连接表.这将有助于提高SQL语句的可读性,同时又避免错误.
一个非常普遍的错误是总是忘记使用JOIN,比如下面的例子:
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紧挨着需要连接的表使用,以避免错误
- 更有表现力,可以在OUTER JOIN,INNER JOIN等等之间明显辨别
总结:
总是使用JOIN,永远不要在FROM从句中使用逗号分隔表.
SQL’s different JOIN operations(SQL中不同的JOIN操作)
JOIN操作的5中不同形式:
- EQUI JOIN
- SEMI JOIN
- ANTI JOIN
- CROSS JOIN
- DIVISION
EQUI JOIN
比较常用的JOIN操作,拥有两个子从句:
- INNER JOIN (or just JOIN)
- OUTER JOIN (further sub-flavoured as 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
….
Lukas Eder: 10 Easy Steps to a Complete Understanding of SQL