SQL入门教程
本文是针对初学者的SQL入门教程,以PostgreSQL为案例从SQL简单到复杂的入门教程。SQL是看上去容易,但是深入后你会发现还是很复杂的,虽然今天在中大型系统中,应用程序逻辑已经替代这些复杂的SQL语句,但是了解它们还是有必要。
SELECT, FROM, 和 WHERE最关键核心的几个关键词,下面我们以借书为案例来说明SQL使用,假设我们有以下数据库:

有一个图书馆,有书籍和会员,我们有另外一个表用于借书。books这个表是包含书籍标题 作者和发布日期以及库存。members表只有会有的姓和名。而borrowings表是记录会员借书信息,bookid代表借书的books的书籍id,而memberid是代表members表中的会员id,有借出日期和归还日期:

简单查询
开始一个简单查询,查询Dan Brown编写的书籍的名称和id:
SELECT bookid AS "id", title FROM books WHERE author='Dan Brown';
输出结果:
| id | title |
|---|---|
| 2 | The Lost Symbol |
| 4 | Inferno |
这里FROM是查询数据的表,WHERE是查询条件,用来过滤查询结果,这里使用author是Dan Brown表示书籍作者是Dan Brown;SELECT则是用来表达如何展现结果,我们可以使用AS来修改要显示的数据列名。
Join
我们希望查询所有Dan Brown编写的书籍的借阅情况,包括归还日期:
SELECTbooks.titleAS"Title",borrowings.returndateAS"Return Date"FROMborrowingsJOINbooksONborrowings.bookid=books.bookidWHEREbooks.author='Dan Brown';
结果如下:
| Title | Return Date |
|---|---|
| The Lost Symbol | 2016-03-23 00:00:00 |
| Inferno | 2016-04-13 00:00:00 |
| The Lost Symbol | 2016-04-19 00:00:00 |
查询语句中大部分类似前面,只是FROM段不一样,这意味着我们不只是单独查询books或borrowings表,而是查询了一个结合join这两个表的新表。
borrowings JOIN books ON borrowings.bookid=books.bookid可以看成是结合了books表和boorowings表的所有数据的另外一个表。只要这些数据有同样的bookid。
下面我们再复杂一些,我们需要借阅Dan Brown编写书籍的每个人的姓名。
第一步:数据从哪里来?FROM怎么写?我们得join member表,和books以及borrowings表:
borrowingsJOINbooksONborrowings.bookid=books.bookidJOINmembersONmembers.memberid=borrowings.memberid
第二步:我们需要显示什么数据?我们仅仅关心作者是Dan Brown的数据:
WHERE books.author='Dan Brown'
第三步:我们如何显示它,现在我们已经得到我们要的数据,只要显示姓名:
SELECTmembers.firstnameAS"First Name",members.lastnameAS"Last Name"
现在,我们将上面三步合并为一个查询:
SELECTmembers.firstnameAS"First Name",members.lastnameAS"Last Name"FROMborrowingsJOINbooksONborrowings.bookid=books.bookidJOINmembersONmembers.memberid=borrowings.memberidWHEREbooks.author='Dan Brown';
查询结果:
| First Name | Last Name |
|---|---|
| Mike | Willis |
| Ellen | Horton |
| Ellen | Horton |
聚合Aggregation
聚合是将多行记录变为一行记录,聚合这个词语本身就是多个聚合成一个,多变一。数据库提供强大的聚合功能,这样可以为不同查询要求将原来分散在多个表中的数据汇聚成有针对性的查询结果。
我们在上面基础上增加新的要求,希望查询借阅Dan Brown编写的书籍的姓名和次数。
SELECTmembers.firstnameAS"First Name",members.lastnameAS"Last Name",count(*)AS"Number of books borrowed"FROMborrowingsJOINbooksONborrowings.bookid=books.bookidJOINmembersONmembers.memberid=borrowings.memberidWHEREbooks.author='Dan Brown'GROUPBYmembers.firstname,members.lastname;
获得结果如下:
| First Name | Last Name | Number of books borrowed |
|---|---|---|
| Mike | Willis | 1 |
| Ellen | Horton | 2 |
所有的聚合操作都是带有GROUP BY语句的,这条语句所做的是将查询的表转换为表的组,每个组对应列的值,在这个案例中,我们将之前练习的结果转换成组,也执行了count这种汇总,这是将多行结果汇总会一个单个值,这里是记录总数,这个值然后属于每个组。
下面是代表我们每个组的聚合结果示意图:

逻辑上结论是:结果中所有字段必须要么是在GROUP BY中指定的,要么有基于这些字段有一个汇聚操作结果(如count)。上面结果中count函数操作于所有行,其他函数像sum或max会只适合操作指定行,如果我们查询每个作者编写书籍的库存:
SELECTauthor,sum(stock)FROMbooksGROUPBYauthor;
结果是:
| author | sum |
|---|---|
| Robin Sharma | 4 |
| Dan Brown | 6 |
| John Green | 3 |
| Amish Tripathi | 2 |
这里的sum函数,只工作在stock这个列,用来统计每个组的所有值。