概述

在 SQL 中,我们最常用的应该就是数据库中数据的查询了。
SELECT 的作用是从一个表或多个表中检索出想要的数据行,在本文中,我们将会围绕数据库查询功能进行展开介绍。

SELECT基础查询

SELECT 可以帮助我们从一个表或多个表中进行数据查询。
我们知道一个数据表是由列(字段名)和行(数据行)组成的,我们要返回满足条件的数据行,就需要在 SELECT 后面加上我们想要查询的列名,可以是一列,也可以是多个列。如果你不知道所有列名都有什么,也可以检索所有列。

数据准备

我们以一个王者荣耀英雄数据表为例进行演示,该表中包含 69 个英雄和 23 个属性值,SQL 下载地址见:https://github.com/cystanford/sql_heros_data
image.png
其中,数据表中这 24 个字段(除了 id 以外),分别代表的含义见下图:
image.png

查询指定列

假设我们想要对指定列进行检索,在 SELECT 后面加上这个列的字段名即可。比如我们想要检索数据表中都有哪些英雄:

  1. SELECT name FROM heros

运行结果(69 条记录)见下图,你可以看到这样就等于单独输出了 name 这一列:
image.png
我们也可以对多个列进行检索,在列名之间用逗号 (,) 分割即可:
image.png
当然,我们也可以直接使用 * 来查询全部的字段:

  1. SELECT * FROM heros

需要注意的是,SELECT * 虽然使用起来非常简单,但是实际上这样也增加了数据库的负担。所以如果我们不需要把所有列都检索出来,还是先指定出所需的列名,因为写清列名,可以减少数据表查询的网络传输量。

设置字段别名

在使用 SELECT 查询的时候,可以给列名起别名。
示例如下:

  1. SELECT
  2. name AS n,
  3. hp_max AS hm,
  4. mp_max AS mm,
  5. attack_max AS am,
  6. defense_max AS dm
  7. FROM heros

image.png
可以看到,运行结果和上面多列检索的运行结果是一样的,只是将列名改成了 n、hm、mm、am 和 dm。
别名的作用是对原有名称进行简化,从而让 SQL 语句看起来更精简。同样我们也可以对表名称起别名,这个在多表连接查询的时候会用到。

查询常数

SELECT 还可以在查询结果中增加一列固定的常数列,这列的取值是我们指定的,而不是从数据表中动态取出的。
这有什么价值呢?事实上,它可以帮助我们整合不同的数据源,用常数列作为这个表的标记,就需要查询常数。
比如说,我们想对 heros 数据表中的英雄名进行查询,同时增加一列字段platform,这个字段固定值为“王者荣耀”,可以这样写:

  1. SELECT '王者荣耀' as platform, name FROM heros

image.png
需要说明的是,如果常数是个字符串,那么使用单引号(‘’)就非常重要了,比如‘王者荣耀’。单引号说明引号中的字符串是个常数,否则 SQL 会把王者荣耀当成列名进行查询,但实际上数据表里没有这个列名,就会引起错误。如果常数是英文字母,比如’WZRY’也需要加引号。如果常数是个数字,就可以直接写数字,不需要单引号。

结果行去重

在数据查询中,我们通常需要对结果中重复的数据行进行去重,这就需要使用 DISTINCT 关键词了:
image.png
需要注意的是:

  • DISTINCT 需要放到所有列名的前面,否则会报错;
  • DISTINCT 其实是对后面所有列名的组合进行去重。

    数据排序

    很多时候,我们需要按照某种顺序进行结果的返回,比如我们想要查询所有的英雄,按照最大生命从高到底的顺序进行排列,就需要使用 ORDER BY 子句。
    我们还是先来看一个示例:

    1. SELECT name, hp_max FROM heros ORDER BY hp_max DESC;

    image.png
    需要注意的是:

  • 排序的列名:ORDER BY 后面可以有一个或多个列名,如果是多个列名进行排序,会按照后面第一个列先进行排序,当第一列的值相同的时候,再按照第二列进行排序,以此类推。

  • 排序的顺序:ORDER BY 后面可以注明排序规则,ASC 代表递增排序,DESC 代表递减排序。如果没有注明排序规则,默认情况下是按照 ASC 递增排序。如果排序字段类型为文本数据,就需要参考数据库的设置方式了,这样才能判断 A 是在 B 之前,还是在 B 之后。比如使用 MySQL 在创建字段的时候设置为 BINARY 属性,就代表区分大小写。
  • 非选择列排序:ORDER BY 可以使用非选择列进行排序,所以即使在 SELECT 后面没有这个列名,你同样可以放到 ORDER BY 后面进行排序。
  • ORDER BY 的位置:ORDER BY 通常位于 SELECT 语句的最后一条子句,否则会报错。

    记录数限制

    在查询过程中,我们可以使用 LIMIT 关键词来约束返回结果的数量。
    示例如下:

    1. SELECT name, hp_max FROM heros ORDER BY hp_max DESC LIMIT 5;

    image.png
    需要注意是的,约束返回结果的数量,在不同的 DBMS 中使用的关键字可能不同。
    约束返回结果的数量可以减少数据表的网络传输量,也可以提升查询效率。如果我们知道返回结果只有 1 条,就可以使用LIMIT 1,告诉 SELECT 语句只需要返回一条记录即可。

    WHERE & HAVING 中的数据过滤

    在数据查询的过程中,我们基本上指定相关的筛选条件对数据进行过滤,查询满足我们期望的数据。其中,用到的就是 WHERE 和 HAVING 子句了,二者支持的查询条件规则是一致的,下面我们来统一进行介绍。
    在条件过滤中,主要支持如下几个功能,我们来依次进行介绍。

    比较运算符

    SQL 中支持的比较运算符的含义你可以参见下面这张表格:
    image.png
    一个简单的比较运算符的过滤示例如下:

    1. SELECT name, hp_max FROM heros WHERE hp_max > 6000
    2. SELECT name, hp_max FROM heros WHERE hp_max BETWEEN 5399 AND 6811
    3. SELECT name, hp_max FROM heros WHERE hp_max IS NULL

    逻辑运算符

    存在多个 WHERE 条件子句,可以使用逻辑运算符进行组合:
    image.png
    我们还是来看一个示例:

    1. SELECT
    2. name, hp_max, mp_max
    3. FROM heros
    4. WHERE hp_max > 6000 AND mp_max > 1700
    5. ORDER BY (hp_max+mp_max) DESC

    需要注意的是,当 WHERE 子句中同时存在 OR 和 AND 的时候,AND 执行的优先级会更高,也就是说 SQL 会优先处理 AND 操作符,然后再处理 OR 操作符。如果想要调整优先级的话,就需要使用到 () 了。 () 优先级最高,其次优先级是 AND,然后是 OR。
    我们来看一个示例:

    1. SELECT name, role_main, role_assist, hp_max, mp_max, birthdate
    2. FROM heros
    3. WHERE (role_main IN ('法师', '射手') OR role_assist IN ('法师', '射手'))
    4. AND DATE(birthdate) NOT BETWEEN '2016-01-01' AND '2017-01-01'
    5. ORDER BY (hp_max + mp_max) DESC

    此处还使用了

  • IN 逻辑运算符,来判断对应字段值是否在可选范围内。

  • DATE 函数,将字段 birthdate 转化为日期类型再进行比较。

    通配符 & LIKE 操作符

    还有一种情况是我们要检索文本中包含某个词的所有数据,这里就需要使用通配符。
    通配符就是我们用来匹配值的一部分的特殊字符。这里我们需要使用到 LIKE 操作符。
    如果我们想要匹配任意字符串出现的任意次数,需要使用(%)通配符。比如我们想要查找英雄名中包含“太”字的英雄都有哪些:

    1. SELECT name FROM heros WHERE name LIKE '%太%'

    image.png
    除了 % 可以用于通配符之外,还可以使用 下划线作为通配符来进行匹配。二者的差异在于:(%)代表零个或多个字符,而()只代表一个字符。
    image.png
    PS:在实际操作过程中,尽量少用通配符,因为它需要消耗数据库更长的时间来进行匹配。即使你对 LIKE 检索的字段进行了索引,索引的价值也可能会失效。

    SQL中常用内置函数

    在 SQL 中我们也可以使用函数对检索出来的数据进行函数操作,比如求某列数据的平均值,或者求字符串的长度等。
    在 SQL 语言中,包括了内置函数和自定义函数。内置函数是系统内置的通用函数,而自定义函数是我们根据自己的需要编写的。接下来,我们会讲解一些常用的 SQL 内置函数。
    我们可以把内置函数分成四类:算术函数、字符串函数、日期函数以及转换函数。下面我们来依次进行讲解。

    算术函数

    算术函数就是对数值类型的字段进行算术运算。常用的算术函数及含义如下表所示:
    image.png
    示例如下:

    1. SELECT ABS(-2);
    2. SELECT MOD(101,3);
    3. SELECT ROUND(37.25,1);

    字符串函数

    常用的字符串函数操作包括了字符串拼接,大小写转换,求长度以及字符串替换和截取等。具体的函数名称及含义如下表所示:
    image.png
    一些简单的示例如下:

    1. SELECT CONCAT('abc', 123);
    2. SELECT LENGTH('你好');
    3. SELECT CHAR_LENGTH('你好');
    4. SELECT LOWER('ABC');
    5. SELECT UPPER('abc');
    6. SELECT REPLACE('fabcd', 'abc', 123);
    7. SELECT SUBSTRING('fabcd', 1,3);

    日期函数

    日期函数是对数据表中的日期进行处理,常用的函数包括:
    image.png
    一些简单的示例如下:

    1. SELECT CURRENT_DATE();
    2. SELECT CURRENT_TIME();
    3. SELECT CURRENT_TIMESTAMP();
    4. SELECT EXTRACT(YEAR FROM '2019-04-03');
    5. SELECT DATE('2019-04-01 12:00:05');

    PS:DATE 日期格式必须是 yyyy-mm-dd 的形式。如果要进行日期比较,就要使用 DATE 函数,不要直接使用日期与字符串进行比较。

    转化函数

    转换函数可以转换数据之间的类型,常用的函数如下表所示:
    image.png
    一些简单的示例如下:

    1. SELECT CAST(123.123 AS DECIMAL);
    2. SELECT CAST(123.123 AS DECIMAL(8,2));
    3. SELECT COALESCE(null,1,2);

    SQL 函数使用注意事项

    尽管 SQL 函数使用起来会很方便,但我们使用的时候还是要谨慎。大部分 DBMS 会有自己特定的函数,这就意味着采用 SQL 函数的代码可移植性是很差的。

    SQL 中的大小写规范

    在 SQL 中,关键字和函数名是不用区分字母大小写的,比如 SELECT、WHERE、ORDER、GROUP BY 等关键字,以及 ABS、MOD、ROUND、MAX 等函数名。
    但是为了统一,这儿有一个关于命名规范的建议:

  • 关键字和函数名称全部大写;

  • 数据库名、表名、字段名称全部小写,并用下划线进行分隔;
  • SQL 语句必须以分号结尾。