本文将详细介绍 SQL 中的四种子句 WHERE / ORDER BY / GROUP BY / HAVING,以及基本运算 / 特殊条件表达式 / 函数 / 聚集函数。

数据过滤 WHERE

基本格式

SELECT 语句可以使用 WHERE 进行数据过滤。格式为:

1
{SELECT 语句} WHERE {条件表达式};
1
SELECT * FROM MovieStar WHERE birthDATE >= "19700101";
1
2
3
4
5
6
7
8
+--------------+-------------+--------+------------+
| name | address | gender | birthDate |
+--------------+-------------+--------+------------+
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 |
| Debra Winger | A way | F | 1978-05-06 |
| Jane Fonda | Turner Av. | F | 1977-07-07 |
+--------------+-------------+--------+------------+

其中条件表达式同样支持常用编程语言中的基本运算。

运算符

基本运算符 语义 补充
= / <> / < / > / <= / >= 比较运算符 注意 = 而非 == ,部分 SQL 支持 !=
NOT / AND / OR 逻辑运算符 优先级 NOT > AND > OR

SQL 支持基本的运算符,如四则运算与括号等,此处略去。

特殊运算符 语义 示例 补充说明
IN 多值查找 WHERE movieType IN ("drama", "sciFic") 常用于子查询,将在其他章节介绍。
EXISTS 集合非空 WHERE EXISTS {子查询} 检测子查询返回是否为空,将在其他章节介绍。
BETWEEN AND 区间比较 WHERE length BETWEEN 120 AND 150 等价于 WHERE 120 <= length AND length <= 150
LIKE 模式匹配 WHERE title LIKE "star %" Mysql 的模式匹配仅支持 % 匹配 ≥0\ge 0 个字符,_ 匹配 11 个字符
IS NULL 为空 WHERE length IS NULL 由于 NULL 在运算中的特殊性,必要时使用 IS NULL

使用运算符进行组合筛选的示例:

1
2
3
4
5
6
7
8
-- 语句过长使用换行可以更加直观
SELECT
*
FROM
Movies
WHERE
title LIKE "star %" AND
(year <= 2000 OR studioName = "Paramount");
1
2
3
4
5
6
7
+--------------------+------+--------+-----------+------------+-----------+
| title | year | length | movieType | studioName | producerC |
+--------------------+------+--------+-----------+------------+-----------+
| Star Trek | 1979 | NULL | sciFic | Paramount | 444 |
| Star Trek: Nemesis | 2002 | 116 | sciFic | Paramount | 321 |
| Star Wars | 1977 | 124 | sciFic | Fox | 555 |
+--------------------+------+--------+-----------+------------+-----------+

计算字段

计算字段与物理字段

计算字段 不存在于物理表中更不占用磁盘,它是在执行查询语句时,基于物理表中的已有字段得到的字段。从效率的角度,计算字段 在执行语句时计算,这样做既节约了内存又方便修改,但在查询时耗费了额外的之间。

计算字段 直接在 SELECT 语句中与物理字段直接替换使用即可,另外建议给计算字段设置别名。

1
SELECT {计算表达式} [AS {别名}] FROM {表名};
1
2
3
4
5
6
7
SELECT 
title,
CONCAT(studioName, " ", movieType, " ", year)
AS description
-- CONCAT 是字符串连接函数, 不同 SQL 版本各不相同
FROM
Movies;
1
2
3
4
5
6
SELECT 
title,
CONCAT(studioName, " ", movieType, " ", year)
-- 没有别名的版本
FROM
Movies;
1
2
3
4
5
6
SELECT 
*, -- 依然可以使用 *
CONCAT(studioName, " ", movieType, " ", year)
AS description
FROM
Movies;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+--------------------------+----------------------------+
| title | description |
+--------------------------+----------------------------+
| Empire Strikes Back | Fox drama 1980 |
| My people,My country | huaxia feature 2019 |
| Gone With the Wind | MGM drama 1938 |
| Logan's run | MGM drama 1977 |
| Pretty Woman | Disney drama 1990 |
| Star Trek | Paramount sciFic 1979 |
| Star Trek: Nemesis | Paramount sciFic 2002 |
| Star Wars | Fox sciFic 1977 |
| Terms of Endearment | MGM drama 1983 |
| The Man Who Wasn't There | USA Entertainm comedy 2001 |
| The Usual Suspects | MGM drama 1995 |
+--------------------------+----------------------------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+--------------------------+-----------------------------------------------+
| title | CONCAT(studioName, " ", movieType, " ", year) |
+--------------------------+-----------------------------------------------+
| Empire Strikes Back | Fox drama 1980 |
| My people,My country | huaxia feature 2019 |
| Gone With the Wind | MGM drama 1938 |
| Logan's run | MGM drama 1977 |
| Pretty Woman | Disney drama 1990 |
| Star Trek | Paramount sciFic 1979 |
| Star Trek: Nemesis | Paramount sciFic 2002 |
| Star Wars | Fox sciFic 1977 |
| Terms of Endearment | MGM drama 1983 |
| The Man Who Wasn't There | USA Entertainm comedy 2001 |
| The Usual Suspects | MGM drama 1995 |
+--------------------------+-----------------------------------------------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+--------------------------+------+--------+-----------+----------------+-----------+----------------------------+
| title | year | length | movieType | studioName | producerC | description |
+--------------------------+------+--------+-----------+----------------+-----------+----------------------------+
| Empire Strikes Back | 1980 | 111 | drama | Fox | 555 | Fox drama 1980 |
| My people,My country | 2019 | 158 | feature | huaxia | 100 | huaxia feature 2019 |
| Gone With the Wind | 1938 | 238 | drama | MGM | 123 | MGM drama 1938 |
| Logan's run | 1977 | 120 | drama | MGM | 888 | MGM drama 1977 |
| Pretty Woman | 1990 | 119 | drama | Disney | 999 | Disney drama 1990 |
| Star Trek | 1979 | NULL | sciFic | Paramount | 444 | Paramount sciFic 1979 |
| Star Trek: Nemesis | 2002 | 116 | sciFic | Paramount | 321 | Paramount sciFic 2002 |
| Star Wars | 1977 | 124 | sciFic | Fox | 555 | Fox sciFic 1977 |
| Terms of Endearment | 1983 | 132 | drama | MGM | 123 | MGM drama 1983 |
| The Man Who Wasn't There | 2001 | 116 | comedy | USA Entertainm | 777 | USA Entertainm comedy 2001 |
| The Usual Suspects | 1995 | 106 | drama | MGM | 999 | MGM drama 1995 |
+--------------------------+------+--------+-----------+----------------+-----------+----------------------------+

函数

此外,各类 SQL 均提供了相关的函数用于计算,这通常被用于计算字段或筛选条件中,例如上面使用到的 CONCAT 函数。但是各类 SQL 中的函数各不相同,因此从可移植性的角度,我们应该尽量减少函数的使用。

下面以 MySQL 为例,举例一些常用函数。

函数 作用 补充
CONVERT(expr, type) 数据类型转换 在其他 SQL 中有 CAST,也有使用多函数的。
函数 作用 补充
SUBSTR(field, start, length) 截取子串 start 是 11 索引的,field 自动转为字符型。
CONCAT(field1, field2) 拼接字符串 field 自动转为字符型。
LENGTH(field) 获取字符串长度 field 自动转为字符型。
LOWER(field) / LOWER(field) 获取字符串大写 / 小写 field 自动转为字符型。
LTRIM(field) / RTRIM(field) / TRIM(field) 去除左 / 右 / 左右空字符 field 自动转为字符型。
SOUNDEX(field) 获取发音,用于查找发音 field 自动转为字符型。
函数 作用 补充
NOW() 获取当前日期时间 2023-10-11 14:32:17
CURDATE() 获取当前日期 2023-10-11
CURTIME() 获取当前时间 14:32:17
DATE(datetime) / TIME(datetime) 获取日期 / 时间 1970-01-01 / 08:00:00
YEAR(datetime) / MONTH(datetime) / DAY(datetime) 获取年 / 月 / 日 1970 / 1 / 1
HOUR(datetime) / MINUTE(datetime) / SECOND(datetime) 获取时 / 分 / 秒 8 / 0 / 0
MONTHNAME(datetime) / DAYNAME(datetime) 获取月份名 / 工作日名 January / Thursday
DATE_FORMAT(datetime, format) 格式化时间输出 %Y-%m-%d %H:%i:%s
UNIX_TIMESTAMP(datetime) 时间类型转时间戳
FROM_UNIXTIME(datetime) 时间戳转时间类型
函数 作用 补充
ABS(num) 绝对值
ROUND(num) / ROUND(num, digit) 四舍五入 / 四舍五入到若干小数
SIN(num) / COS(num) / TAN(num) 三角函数
EXP(num) / LOG(num) 自然指数与自然对数
POW(base, exponent) / LOG(base, real) / SQRT(base) 指数与对数与开方
EXP(1) / PI() 自然底数与圆周率

数据排序 ORDER BY

基本格式

SELECT 语句可以使用 ORDER BY 进行数据排序。格式为:

1
{SELECT 语句} [WHERE {条件表达式}] ORDER BY {排序关键字};

​注意事项:

  • 排序关键字可以是计算字段,即一个表达式。
  • 如果未使用 ORDER BY,关键字应当被假定是无序的;但主键总是排序的。
1
SELECT * FROM MovieStar;  -- 未排序前的状态
1
SELECT * FROM MovieStar ORDER BY birthDate;
1
SELECT * FROM Movies ORDER BY length * producerC;  -- 可以是计算字段
1
2
3
4
5
6
7
8
9
10
+----------------+-------------+--------+------------+
| name | address | gender | birthDate |
+----------------+-------------+--------+------------+
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 |
| Debra Winger | A way | F | 1978-05-06 |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 |
| Jack Nicholson | X path | M | 1949-05-05 |
| Jane Fonda | Turner Av. | F | 1977-07-07 |
+----------------+-------------+--------+------------+
1
2
3
4
5
6
7
8
9
10
+----------------+-------------+--------+------------+
| name | address | gender | birthDate |
+----------------+-------------+--------+------------+
| Jack Nicholson | X path | M | 1949-05-05 |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 |
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 |
| Jane Fonda | Turner Av. | F | 1977-07-07 |
| Debra Winger | A way | F | 1978-05-06 |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 |
+----------------+-------------+--------+------------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+--------------------------+------+--------+-----------+----------------+-----------+
| title | year | length | movieType | studioName | producerC |
+--------------------------+------+--------+-----------+----------------+-----------+
| Star Trek | 1979 | NULL | sciFic | Paramount | 444 |
| My people,My country | 2019 | 158 | feature | huaxia | 100 |
| Terms of Endearment | 1983 | 132 | drama | MGM | 123 |
| Gone With the Wind | 1938 | 238 | drama | MGM | 123 |
| Star Trek: Nemesis | 2002 | 116 | sciFic | Paramount | 321 |
| Empire Strikes Back | 1980 | 111 | drama | Fox | 555 |
| Star Wars | 1977 | 124 | sciFic | Fox | 555 |
| The Man Who Wasn't There | 2001 | 116 | comedy | USA Entertainm | 777 |
| The Usual Suspects | 1995 | 106 | drama | MGM | 999 |
| Logan's run | 1977 | 120 | drama | MGM | 888 |
| Pretty Woman | 1990 | 119 | drama | Disney | 999 |
+--------------------------+------+--------+-----------+----------------+-----------+

升序与降序

ORDER BY 可以使用 ASC(默认)/ DESC 表示升序和降序,将其放在排序关键字后面。

1
SELECT * FROM MovieStar ORDER BY birthDate ASC;
1
SELECT * FROM MovieStar ORDER BY birthDate DESC;
1
2
3
4
5
6
7
8
9
10
+----------------+-------------+--------+------------+
| name | address | gender | birthDate |
+----------------+-------------+--------+------------+
| Jack Nicholson | X path | M | 1949-05-05 |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 |
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 |
| Jane Fonda | Turner Av. | F | 1977-07-07 |
| Debra Winger | A way | F | 1978-05-06 |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 |
+----------------+-------------+--------+------------+
1
2
3
4
5
6
7
8
9
10
+----------------+-------------+--------+------------+
| name | address | gender | birthDate |
+----------------+-------------+--------+------------+
| Kim Basinger | Baldwin Av. | F | 1979-05-07 |
| Debra Winger | A way | F | 1978-05-06 |
| Jane Fonda | Turner Av. | F | 1977-07-07 |
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 |
| Jack Nicholson | X path | M | 1949-05-05 |
+----------------+-------------+--------+------------+

多关键字排序

ORDER BY 可以添加多个排序关键字,直接使用 , 分割即可:

1
{SELECT 语句} [WHERE {条件表达式}] ORDER BY {排序关键字} [ASC / DESC] [, {排序关键字} [ASC / DESC] ...];
1
SELECT * FROM MovieExec ORDER BY netWorth ASC, address DESC;
1
2
3
4
5
6
7
8
9
10
11
+-------------------+-------------+------+-----------+
| name | address | cert | netWorth |
+-------------------+-------------+------+-----------+
| Huangjianxin | NULL | 100 | NULL |
| Calvin Coolidge | Fast Lane | 123 | 20000000 |
| Stephen Spielberg | 123 ET road | 222 | 100000000 |
| Merv Griffin | Riot Rd. | 199 | 112000000 |
| Ted Turner | Turner Av. | 333 | 125000000 |
| Jane Fonda | Turner Av. | 567 | 200000000 |
| George Lucas | Oak Rd. | 555 | 200000000 |
+-------------------+-------------+------+-----------+

分页查询 LIMIT OFFSET

当数据表很大时,直接显示整张数据表不太现实,例如直接查询千万记录级别的数据表,可能直接导致内存爆炸。这时我们可以使用分页查询,仅显示数据表中一定数量的行。

1
{SELECT 语句} LIMIT {显示行数} [OFFSET {首行行号}]

注意行号是 0 索引的,LIMIT OFFSET 的两个参数都是非负数,OFFSET 可缺省为 0。

1
2
3
SELECT COUNT(*) FROM test;
SELECT * FROM test LIMIT 10 OFFSET 0;
SELECT * FROM test LIMIT 10 OFFSET 10; -- 一般 OFFSET 是 LIMIT 的倍数
1
2
3
4
5
+----------+
| COUNT(*) |
+----------+
| 511232 |
+----------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
+----+----------+------+
| id | name | age |
+----+----------+------+
| 0 | wangwu | 11 |
| 1 | wangwu | 33 |
| 2 | wangwu | 10 |
| 3 | lisi | 21 |
| 4 | zhangsan | 43 |
| 5 | zhangsan | 48 |
| 6 | zhangsan | 30 |
| 7 | lisi | 50 |
| 8 | lisi | 20 |
| 9 | zhangsan | 29 |
+----+----------+------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
+----+----------+------+
| id | name | age |
+----+----------+------+
| 10 | zhangsan | 10 |
| 11 | lisi | 24 |
| 12 | zhangsan | 27 |
| 13 | lisi | 36 |
| 14 | zhangsan | 14 |
| 15 | wangwu | 47 |
| 16 | wangwu | 16 |
| 17 | zhangsan | 40 |
| 18 | wangwu | 19 |
| 19 | zhangsan | 23 |
+----+----------+------+

聚集函数与分组

聚集函数

聚集函数用于汇总数据,SQL 提供了 55 种聚集函数。另外,在不同 SQL 版本中,函数名可能各有不同。

聚集函数 功能 补充
COUNT(field) 字段非空值数量 参数可为 *,计数表格行数,即使整行均为 NULL 也计数,使用 DISTINCT 也计数全部行数。仅 COUNT 参数可 *
MIN(field) 字段最小值 NULL 值忽略,全 NULL 返回 NULL
MAX(field) 字段最大值 NULL 值忽略,全 NULL 返回 NULL
SUM(field) 字段求和 NULL 值忽略,全 NULL 返回 NULL
AVG(field) 字段平均值 =SUM()COUNT()=\frac{\text{SUM}()}{\text{COUNT}()},COUNT()=0\text{COUNT}()=0 返回 NULL
VAR_POP(field) 字段标准差 =AVG(POW(X−AVG(), 2))= \text{AVG}(\text{POW}(X - \text{AVG}(),~2)),COUNT()=0\text{COUNT}()=0 返回 NULL
STDDEV(field) 字段标准差 =SQRT(VAR_POP())= \text{SQRT}(\text{VAR\_POP}()),COUNT()=0\text{COUNT}()=0 返回 NULL
GROUP_CONCAT(field [SEPARATOR separator]) 字段值连接 将该分组该字段的值按分隔符连接,分隔符可缺省为 ,

​注释: 聚集函数的对象为分组,分组使用下一章节中的 GROUP BY 创建,是一些具有相同属性的行的集合。未创建分组的,全部行为一个分组,因此在目前的示例中我们都只能看到一行输出。

1
SELECT MIN(year), MAX(year), COUNT(length), SUM(producerC), AVG(producerC) FROM Movies;
1
2
3
4
5
6
7
8
SELECT 
MIN(year) AS minYear,
MAX(year) AS maxYear,
COUNT(length) AS cntLength,
SUM(producerC) AS sumProducerC,
AVG(producerC) AS avgProducerC
FROM
Movies;
1
2
3
4
5
+-----------+-----------+---------------+----------------+----------------+
| MIN(year) | MAX(year) | COUNT(length) | SUM(producerC) | AVG(producerC) |
+-----------+-----------+---------------+----------------+----------------+
| 1938 | 2019 | 10 | 5884 | 534.9091 |
+-----------+-----------+---------------+----------------+----------------+
1
2
3
4
5
+---------+---------+-----------+--------------+--------------+
| minYear | maxYear | cntLength | sumProducerC | avgProducerC |
+---------+---------+-----------+--------------+--------------+
| 1938 | 2019 | 10 | 5884 | 534.9091 |
+---------+---------+-----------+--------------+--------------+

分组聚集 GROUP BY

基本格式

GROUP BY 用于设置分组,分组是一些具有相同属性的行的集合,分组是聚集函数的计算范围。在输出的表格中每个分组为一行,使用 GROUP BY 才能发挥出聚集函数的作用。

1
{SELECT 语句} GROUP BY {分组关键字};

GROUP BY 同样支持多关键字。

1
{SELECT 语句} GROUP BY {分组关键字} [, 分组关键字];
1
2
SELECT studioName, COUNT(length) FROM Movies GROUP BY studioName; 
-- 使用聚合函数计数某工作室出品的电影中有记录电影时长的数量
1
2
SELECT studioName, movieType, COUNT(*) FROM Movies GROUP BY studioName, movieType;
-- 使用聚合函数计数某工作室出品的某类型电影的数量
1
2
3
4
5
6
7
8
9
10
+----------------+---------------+
| studioName | COUNT(length) |
+----------------+---------------+
| Fox | 2 |
| huaxia | 1 |
| MGM | 4 |
| Disney | 1 |
| Paramount | 1 |
| USA Entertainm | 1 |
+----------------+---------------+
1
2
3
4
5
6
7
8
9
10
11
+----------------+-----------+----------+
| studioName | movieType | COUNT(*) |
+----------------+-----------+----------+
| Fox | drama | 1 |
| huaxia | feature | 1 |
| MGM | drama | 4 |
| Disney | drama | 1 |
| Paramount | sciFic | 2 |
| Fox | sciFic | 1 |
| USA Entertainm | comedy | 1 |
+----------------+-----------+----------+

注意事项

  • GROUP BY 不会进行排序的工作,它的分组依然是乱序的。
  • SELECT 语句中的字段必须是分组关键字、引用 以物理字段作 分组关键字的计算字段、聚集函数。需要注意的是,如果分组关键字是计算字段,SELECT 语句中的计算字段不能引用它,但聚集函数的参数可以任意引用。

以下是一些关于第二条的示例,有正有误:

1
SELECT * FROM Movies GROUP BY studioName;
显示答案

错误,部分物理字段不属于分组关键字。

分析 SQL 这样做的原因,由于每个分组使用单行显示,并且分组内仅保证相同属性 studioName,因此无法确定的输出其他字段(如 title 字段)。

1
SELECT CONCAT(studioName, " ", movieType), COUNT(*) FROM Movies GROUP BY studioName, movieType;
显示答案

正确,计算字段是对分组关键字的引用。

分析 SQL 这样做的原因,每个分组内保证相同属性 studioName 和 movieType,因此可以确定输出 UPPER(studioName) 字段。

1
2
3
4
5
6
7
8
9
10
11
+------------------------------------+----------+
| CONCAT(studioName, " ", movieType) | COUNT(*) |
+------------------------------------+----------+
| Fox drama | 1 |
| huaxia feature | 1 |
| MGM drama | 4 |
| Disney drama | 1 |
| Paramount sciFic | 2 |
| Fox sciFic | 1 |
| USA Entertainm comedy | 1 |
+------------------------------------+----------+
1
2
3
4
5
6
7
SELECT 
CONCAT(studioName, " ", movieType),
COUNT(*)
FROM
Movies
GROUP BY
CONCAT(studioName, " ", movieType);
显示答案

正确,计算字段是分组关键字。

虽然是计算字段,但是对于 SQL 而言由于两个字段完全相同,直接引用即可。

1
2
3
4
5
6
7
8
9
10
11
+------------------------------------+----------+
| CONCAT(studioName, " ", movieType) | COUNT(*) |
+------------------------------------+----------+
| Fox drama | 1 |
| huaxia feature | 1 |
| MGM drama | 4 |
| Disney drama | 1 |
| Paramount sciFic | 2 |
| Fox sciFic | 1 |
| USA Entertainm comedy | 1 |
+------------------------------------+----------+
1
2
3
4
5
6
7
SELECT 
UPPER(CONCAT(studioName, " ", movieType)),
COUNT(*)
FROM
Movies
GROUP BY
CONCAT(studioName, " ", movieType);
显示答案

错误,计算字段不能引用 GROUP BY 中的计算字段,只能直接相等(如示例3)。

从 SQL 实现的角度考虑,显然在进行 UPPER 操作后我们可以唯一的确定输出的值,但是当两个计算字段之间的逻辑变得复杂时,程序很难再推导出两个计算字段之间的关系,于是 SQL 索性禁止了所有此类行为。

1
2
3
4
5
6
7
SELECT 
movieType,
AVG(length * producerC)
FROM
Movies
GROUP BY
movieType;
显示答案

正确,聚合函数可以任意的引用和计算。因为聚合函数的本质就是将数据汇总输出一个值。

1
2
3
4
5
6
7
8
+-----------+-------------------------+
| movieType | AVG(length * producerC) |
+-----------+-------------------------+
| drama | 73075.0000 |
| feature | 15800.0000 |
| sciFic | 53028.0000 |
| comedy | 90132.0000 |
+-----------+-------------------------+

分组过滤 HAVING

与 WHERE 不同的是,HAVING 过滤的对象是分组,而 WHERE 的过滤对象为行。HAVING 通常与 GROUP BY 一同使用,必须放在 GROUP BY 之后。如果你无法很好的区分 WHERE 和 HAVING 只需要记住,在 GROUP BY 之前进行的筛选是 WHERE,在 GROUP BY 之后进行的筛选是 HAVING。

1
{SELECT 语句} GROUP BY {分组关键字} HAVING {条件表达式}

由于 HAVING 过滤的对象是分组。在 HAVING 条件表达式中,可以使用聚集函数;而在 WHERE 条件表达式中,不可使用聚集函数。但 HAVING 条件表达式中的引用具有与前面提到的 GROUP BY 相同的约束,详见 分组聚集 GROUP BY - 注意事项。

1
2
3
4
5
6
7
8
9
10
SELECT 
studioName,
COUNT(*)
FROM
Movies
GROUP BY
studioName
HAVING
COUNT(*) > 1 AND
LENGTH(studioName) > 3;
1
2
3
4
5
+------------+----------+
| studioName | COUNT(*) |
+------------+----------+
| Paramount | 2 |
+------------+----------+

SELECT 子句顺序

至此我们介绍了 44 种子句,SQL 严格定义了这些关键字的顺序。SELECT 查询命令也是按照这个顺序从左往右执行的。

关键字 作用 顺序级
WHERE 行级过滤 1
GROUP BY 分组 2
HAVING 组级过滤 3
ORDER BY 排序 4
LIMIT OFFSET 分页查询 5

下面算是一个综合应用吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT 
studioName,
COUNT(*)
FROM
Movies
WHERE
year >= 1950 -- 首先去除 1950 年前的作品
GROUP BY
studioName -- 然后将剩余作品按工作室分组
HAVING
COUNT(*) > 1 -- 再去掉分组后分组包含作品 <= 1 的工作室
ORDER BY
COUNT(*) DESC, -- 最后将数据集按作品数降序, 工作室名称升序排列
studioName;
1
2
3
4
5
6
7
+------------+----------+
| studioName | COUNT(*) |
+------------+----------+
| MGM | 3 |
| Fox | 2 |
| Paramount | 2 |
+------------+----------+