SQL语言是一门相对来说简单易学却又功能强大的语言,它能让你快速上手并很快就能写出比较复杂的查询语句。但是对于大多数开发者来说,使用SQL语句查询数据库的时候,如果没有一个抽象的过程和一个合理的步骤,很可能会在写一些特定的SQL查询语句来解决特定问题的时候被卡住。

这里主要讲述下SQL查询的一些基本理论,以及写查询语句的抽象思路。

SQL查询的简介

SQL语言起源于1970年E.J.Codd发表的关系数据库理论,所以可以说SQL是为关系数据库服务的。而对于SQL查询,是指从数据库中取得数据的子集。

子集指的就是从一个或多个表中提取特定的字段和字段对应的记录。

可以说,SQL中无论多复杂的查询,都可以抽象成如上面的过程。

精确查询的前置条件

想要正确取得所需要的数据子集,除了需要思路正确并将思路正确转变为对应SQL查询语句之外,还有很重要的一点是需要数据库有着良好的设计。这里的良好设计指的是数据库的设计符合业务逻辑。如果数据库设计得很烂,那数据查询起来就很困难,要达到精确查询也就变得困难起来。

举个简单的例子,A表中有a字段,B表中也有a字段,在业务处理的过程中,A表中的a字段可能和B表中的a字段发生了分歧,这时候是要取A表中的a字段的值还是取B表中的a字段的值,也就成了一个问题。

两种方式,同一种结果

在SQL中,取得相同的数据子集可以用不同的思路或不同的SQL语句,因为SQL源于关系数据库理论,而关系数据库理论又源于数学,思考如何构建查询语句时,都可以抽象为两种方法。

关系代数法

关系代数法的思路是对数据库进行分步操作,最后取得想要的结果。

SELECT NAME FROM USERS WHERE AGE > 20;

关系代数的思路描述上面语句为:对USERS表进行投影(选择列)操作,然后对结果进行筛选,只取得年龄大于20的结果。

关系演算法

相比较关系代数法而言,关系演算法更多关注的是取得数据所满足的条件。比如上面SQL用关系演算法可以被描述为:我想得到所有年龄大于20的员工的姓名,部门和年龄。

两种算法的区别

对于简单的查询语句来说,上面两种方法都不需要,因为可能用脚就可以想出来了,只是问题在于很多情况下查询语句会非常复杂,这时候就用两种算法去区分描述的优势才会表现出来。

对于关系演算法来说,更多关注的是所取出信息所满足的条件;而对于关系代数法来说,更多关注的是如何取出特定的信息。简单地说,关系演算法表示的是【what】,而关系代数法表达的是【how】。SQL语句中所体现的思路,有些时候是关系代数法,有些时候是关系演算法,还有些会是两种思路的混合。

对于某些查询情况,关系代数法可能会更简单;而对于另外一些情况,关系演算法则会显得更直接;还有一些情况则是需要混合两种思路。所以这两种思维方式在写SQL查询时都是必须要掌握的。

单表查询

单表查询是所有查询中的中间状态,即使是多个表的复杂查询,在进行各种连接后最终都能够被抽象成单表查询。所以先从单表查询开始。

选择列的子集

根据上面数据子集的说法,选择列是通过在SELECT语句后面添加所要选择的列名实现的。

SELECT NAME FROM USERS;

选择行的子集

选择行的子集,是在SQL语句的WHERE子句后面加上相应的限制条件。当WHERE子句后面的表达式为【真/true】时,也就是满足所谓的【条件】时,返回相应的行的子集。

WHERE子句后面的运算符分为两类,分别是比较运算符和逻辑运算符。

比较运算符是将两个相同类型的数据进行比较,进而返回布尔类型(boolean)的运算符。在SQL中,比较运算符一共有六种,分别是等于(=)、小于(<)、小于或等于(<=)、大于或等于(>=)以及不等于(<>)。其中,小于或等于和大于或等于可以看成是比较运算符和逻辑运算符的结合体。

SELECT NAME FROM USERS WHERE AGE >= 18;

逻辑运算符是将两个布尔类型进行连接,并返回一个新的布尔类型的运算符。在SQL中,逻辑运算符通常是将比较运算符返回的布尔类型相连接以最终确定WHERE子句后面满足条件的真假。逻辑运算符一共有三种,分别是与(AND)、或(OR)和非(NOT)。其中,非运算符可以看作是特殊的比较运算符。

SELECT NAME FROM USERS WHERE AGE > 18 AND AGE < 60;

另外,这几种运算符是有优先级的,优先级由大到小排列,是比较运算符>于逻辑运算符(AND)>或逻辑运算符(OR)。当然,也可以通过括号运算符来改变优先级,括号运算符的优先级最高。

1+1≠2的问题

假定USERS表中存在一个SEX(性别)字段,我们一般可能会认为,这个世界不是男人就是女人,因此SEX字段就只能有male和female两种值。

SELECT *