10 Easy Steps to a Complete Understanding of SQL

简介

很多程序员视SQL如猛兽.它是为数不多的声明式语言的一种,它的表现形式与一些面向对象语言或者函数式语言完全不同.

这篇文章主要会关注 SELECT语句.

SQL is declarative(SQL是声明性的)

把这个概念放在脑子里,声明性.唯一的一个范例就是,你只是以”声明”的性质来获取你想要的结果.而不是你的电脑如何计算出这些结果.

SELECT first_name, last_name 
FROM employees 
WHERE salary > 100000

这很容易理解,你并不关系员工的档案是从哪来的.你仅仅想要拿到那些在薪水范围内的员工信息.

总结:

问题在于我们通常认为这是在进行命令式的编程.比如: “机器,做这个,然后做那个,但是开始之前,先做一个检查,如果怎样怎样就失败”.这些包含了,在变量中保存缓存结果,编写循环,迭代,调用函数等等.

丢掉这些想法,然后思考如何使用声明的方式.而不是告诉机器如何去计算.

SQL syntax is not “well-ordered”(SQL的语法并不是井然有序的)

一个普遍困惑的来源就是,SQL中的语法元素顺序完全不同于其执行顺序.

词汇的排序方式如下:

  1. SELECT [ DISTINCT ]
  2. FROM
  3. WHERE
  4. GROUP BY
  5. HAVING
  6. UNION
  7. ORDER BY

为了简单,并没有列出所有的SQL子句.这些词汇顺序跟逻辑顺序有很大的不同(或者跟执行的顺序相反,取决于有效的选择):

  1. FROM
  2. WHERE
  3. GROUP BY
  4. HAVING
  5. SELECT
  6. DISTINCT
  7. UNION
  8. ORDER BY

有三点需要注意的地方:

  1. FROM 作为了第一个子句,而不是 SELECT.发生的第一件事就是将数据从磁盘加载到内存,以便于对这些数据进行操作.

  2. 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
    
  3. 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语法的有点:

  1. 安全,可以将JOIN紧挨着需要连接的表使用,以避免错误
  2. 更有表现力,可以在OUTER JOIN,INNER JOIN等等之间明显辨别

总结:

总是使用JOIN,永远不要在FROM从句中使用逗号分隔表.

SQL’s different JOIN operations(SQL中不同的JOIN操作)

JOIN操作的5中不同形式:

  1. EQUI JOIN
  2. SEMI JOIN
  3. ANTI JOIN
  4. CROSS JOIN
  5. DIVISION

EQUI JOIN

比较常用的JOIN操作,拥有两个子从句:

  1. INNER JOIN (or just JOIN)
  2. 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