第一章:了解MySQL

模式(schema) 关于数据库和表的布局及特性的信息。
表具有一些特性,这些特性定义了数据在表中如何存储,如可以存储什么样的数据,数据如何分解,各部分信息如何命名,等等。描述表的这组信息就是所谓的模式,模式可以用来描述数据库中特定的表以及整个数据库(和其中表的关系)。

主键:表中每一行中可以唯一标识自己的一列(或一组列)。
虽然不是每张表都需要设置一个主键,但是强烈推荐每张表都要设置一个主键

主键约束:==唯一并且非空==

第二章:MySQL简介

DBMS可分为两类:一类为基于共享文件系统的DBMS,另一类为基于客户机—服务器的DBMS
MySQL、Oracle以及Microsoft SQL Server等数据库是基于客户机—服务器的数据库。
客户机—服务器应用分为两个不同的部分。服务器部分是负责所有数据访问和处理的一个软件。这个软件运行在称为数据库服务器的计算机上。

与数据文件打交道的只有服务器软件。关于数据、数据添加、删除 和数据更新的所有请求都由服务器软件完成。这些请求或更改来自运行 客户机软件的计算机。客户机是与用户打交道的软件。例如,如果你请 求一个按字母顺序列出的产品表,则客户机软件通过网络提交该请求给 服务器软件。服务器软件处理这个请求,根据需要过滤、丢弃和排序数 据;然后把结果送回到你的客户机软件

第三章:使用MySQL

为了连接到MySQL,需要以下信息:

  1. 主机名(计算机名)——如果连接到本地MySQL服务器,为localhost;
  2. 端口(如果使用默认端口3306之外的端口);
  3. 一个合法的用户名;
  4. 用户口令(如果需要)。

1554780061764

如果是使用命令行(称为MySQL monitor)打开数据库,那么就需要键入:

1
mysql -hlocalhost -uroot -p5KVp2y7,k96o

-h表示主机,-u表示用户名,-p表示密码
1554780901574

要注意一点的就是,在命令行输入语句的时候一定要在最后加上分号:

1554780972595

USE关键字:用于选择一个数据库
1554781347428


show的用法:

1
2
3
4
# 展示全部数据库
show databases;
# 展示某个数据库中的全部表
show tables
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 展示acglist表中的全部列
show columns from acglist;
/*
+-------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| title | varchar(255) | NO | | NULL | |
| sort | varchar(255) | NO | | NULL | |
| size | varchar(255) | NO | | NULL | |
| releasetime | varchar(255) | NO | | NULL | |
| publisher | varchar(255) | NO | | NULL | |
| magnet | varchar(255) | NO | PRI | NULL | |
+-------------+--------------+------+-----+---------+-------+
*/
1
2
3
4
5
6
7
8
9
10
11
12
# 显示广泛的服务器状态信息
show status
# 显示创建特定数据库
show create database
# 显示创建特定数据表
show create table
# 显示授予用户(所有用户或特定用户)的安全权限
show grants
# 显示服务器错误消息
show errors
# 显示服务器警告消息
show warnings

show columns from acglist;有语法糖:

1
describe acglist;

第四章:检索数据

本章讲select

1
2
3
4
5
6
7
8
# 注意这里select的是[列]
select col from table1
# 查找唯一值
select DISTINCT col from table2
# 限定检索的数量
select name from new_list limit 5;
# 检索从第5行(不含)开始的6行(就是6-11行)
select name from new_list limit 5, 6;

注意,对两列使用distinct,只有那么只有当两列都相同的时候才不会被检索出来

1
select distinct id name from new_list

注意:MySQL和很多语言一样,第一行的index是0不是1.所以select name from new_list limit 5, 6;严格来讲是检索从第5行(包含)开始的6行

1
2
# 这种加了点号的写法被称为'完全限定'
select new_list.id from iremenberspider.new_list

第五章:排序检索数据

本章讲order by

我们检索的数据一般将以它在底层表中出现的顺序显示.
如果数据后来进行过更新或删除,则此顺 序将会受到MySQL重用回收存储空间的影响。

子句(clause)SQL语句由子句构成,有些子句是必需的,而有的是可选的.
ORDER BY子句取一个或多个列的名字,据此对输出进行排序

1
select id from new_list order by name

为了统一,本章开始都使用下面的表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
+-------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| title | varchar(255) | NO | | NULL | |
| id | int(11) | NO | PRI | NULL | |
| commic_url | varchar(255) | NO | | NULL | |
| cover_url | varchar(255) | NO | | NULL | |
| tags | varchar(255) | NO | | NULL | |
| page | smallint(6) | NO | | NULL | |
| artists | varchar(255) | NO | | NULL | |
| categories | varchar(255) | NO | | NULL | |
| languages | varchar(255) | NO | | NULL | |
| upload_time | varchar(255) | NO | | NULL | |
+-------------+--------------+------+-----+---------+-------+

Excel里排序有首要关键词,吃药关键字等
(例如,如果要显示雇员清单,首先按姓排序,然后在每个姓中再按名排序)

1
2
# 排序id和languages.首要关键字是page,次要关键字是tags,再次关键字是id
select id,languages from commic_list order by page,tags,id

order by默认是升序.如果要降序必须使用DESC

1
select id,page from commic_list order by id,page DESC limit 5;

如果是多列检索,某列升序,某列降序的话:

1
2
3
# 排序id,page
# id为首要关键字,降序.page为次要关键字,升序
select id,page from commic_list order by id DESC ,page limit 5

DESC关键字只应用到直接位于其前面的列名,哪列要降序就加到哪列上面.
如果想在多个列上进行降序排序,必须对每个列指定DESC关键字

与DESC相反的关键字是ASC(ASCENDING),在升序排序时可以指定它。 但实际上,ASC没有多大用处,因为升序是默认的

使用ORDER BY和LIMIT的组合,能够找出一个列中最高或最低的值。 eg:找出最昂贵物品的值

第六章 过滤数据

本章将where

在SELECT语句中,数据根据WHERE子句中指定的搜索条件进行过滤。

1
2
3
4
5
6
7
# 注意order by在最后面
select id,page from commic_list where page=17 order by id
# 字符串要加引号(单双引都行)
select id from commic_list where languages="english";
# 注意使用between and,between and包括上下限
# 使用between and的时候没有where
select id,page from commic_list where page between 17 and 20 order by id;

空值检查:is null

1
2
# 空值检查使用is null
select id from commic_list where artists is null

第七章:数据过滤

本章讲NOT和IN操作符,AND子句的方式或OR子句

1
2
3
4
5
6
# and操作符
select id from commic_list where page < 17 and languages='english'
# IN操作符用来指定条件范围.
# 注意:这里就算page是int类型,查找出来的page只会是17和20.并不是17-20
select id,page from commic_list where page in (17,20)
select id,page from commic_list where languages in ('english','japanese');

和python一样,MySQL的and优先级大于or.

1
2
3
# 虽然下面两个是一样的效果,但是IN操作符一般比OR操作符清单执行更快
select id,page from commic_list where page in (17,20)
select id,page from commic_list where page = 17 or page = 20

not 可以放在between and可以避免使用or

1
2
3
# 虽然下面两个是一样的效果,但是not between and更直观
select id,page from commic_list where page not between 17 and 20
select id,page from commic_list where page > 20 or page < 17

第八章:使用通配符进行过滤

本章介绍通配符和LIKE

通配符 描述
% 替代 0 个或多个字符
_ 替代一个字符
[charlist] 字符列中的任何单一字符
[^charlist] 或 [!charlist] 不在字符列中的任何单一字符
1
2
# 搜索以tags字段包含na的记录
select id,tags from commic_list where tags like '%na%';

尾空格可能会干扰通配符匹配。
例如,在保存词 anvil时,如果它后面有一个或多个空格,则子句WHERE prod_name LIKE ‘%anvil’将不会匹配它们,因为在最后的l 后有多余的字符。解决这个问题的一个简单的办法是在搜索模式最后附加一个%。一个更好的办法是使用函数去掉首尾空格。

%与_不能匹配Null.因为Null不是字符.

因为数据是从左向右扫描的,所以建议通配符不要放在第一位

第九章:用正则表达式进行搜索

本章介绍WHERE子句内使用正则表达式

使用正则表达式不再使用LIKE,而是REGEXP

模式 描述
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。
. 匹配除 “\n” 之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用象 ‘[.\n]’ 的模式。
[…] 字符集合。匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。
[^…] 负值字符集合。匹配未包含的任意字符。例如, ‘[^abc]‘ 可以匹配 “plain” 中的’p’。
p1|p2|p3 匹配 p1 或 p2 或 p3。例如,’z|food’ 能匹配 “z” 或 “food”。’(z|f)ood’ 则匹配 “zood” 或 “food”。
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,’zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
0个或1个匹配。?等价于{0,1}
{n} n 是一个非负整数。匹配确定的 n 次。例如,’o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。

注意:mysql用\转义时,要使用两个\,因为mysql要解释一个,然后正则要解释一个。

1
2
3
4
# 查找所有以(开头的记录
select id,title from commic_list where title regexp "^\\(";
# page字段必须是12或14或16
select id,page from commic_list where page regexp '(12|14|16)$';

mysql里的反斜杠\因为要被mysql解释一个,所以,这也影响到了元字符

元字符 说明
\\f 换页
\\n 换行
\\r 回车
\\t 制表
\\v 纵向制表

值得一提的是反斜杠\就会变成三联杠\\\

LIKE和REGEXP的区别:
LIKE是全字符串匹配.REGEXP是部分匹配.
select * from commic_list where id like 123%78
当id是1234789的时候是匹配不到的.
select * from commic_list where id regexp '^123.'
当id是12345的时候还是能匹配的到的.

简单来说,==LIKE匹配整个串,而REGEXP匹配子串==

注意MySQL中的正则表达式默认是不区分大小写的,否则要使用binary关键字

1
2
# title字段必须以大写A开头
select * from commic_list where title regexp binary '^A'

MySQL中的正则表达式被阉割的很厉害.
没有\d,要使用[0-9]
没有\w,要使用[a-zA-Z0-9]

1554807936805

MySQL的正则表达式的定位符元字符多了两个东西:

元字符 说明
^ 文本的开始
$ 文本的结束
[[:<:]] 词的开始
[[:>:]] 词的结束

第十章:创建计算字段

本章介绍什么是计算字段,如何创建计算字段以及怎样从应用程序中使用别名引用它们。

Concat():拼接(concatenate) 将值联结到一起构成单个值
(相当于python里的+)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 新建一个字段,该字段形如258126(22),是id和page和左右括号的合成
select concat(id,'(',page,')'),languages from commic_list limit 5;
/*结果如下
+-------------------------+-----------+
| concat(id,'(',page,')') | languages |
+-------------------------+-----------+
| 258126(22) | japanese |
| 258127(17) | english |
| 258128(20) | english |
| 258129(20) | english |
| 258130(17) | english |
+-------------------------+-----------+
*/

RTrim()函数:删除数据右侧多余的空格(所以还有LTrim和Trim函数)

1
2
3
4
5
6
7
8
9
10
11
12
select concat(RTrim(id),'(',Trim(page),')'),languages from commic_list limit 5;
/*结果如下:
+--------------------------------------+-----------+
| concat(RTrim(id),'(',Trim(page),')') | languages |
+--------------------------------------+-----------+
| 258126(22) | japanese |
| 258127(17) | english |
| 258128(20) | english |
| 258129(20) | english |
| 258130(17) | english |
+--------------------------------------+-----------+
*/

使用别名:别名用AS关键字赋予
别名又叫做导出列(derived column)

1
2
3
4
5
6
7
8
9
10
11
12
select concat(RTrim(id),'(',Trim(page),')')as new_column,languages from commic_list limit 5;
/*结果如下:
+------------+-----------+
| new_column | languages |
+------------+-----------+
| 258126(22) | japanese |
| 258127(17) | english |
| 258128(20) | english |
| 258129(20) | english |
| 258130(17) | english |
+------------+-----------+
*/

执行算术计算:

1
2
3
4
5
6
7
8
9
10
11
12
select id,page,id*page as new_column from commic_list limit 5;
/*结果如下:
+--------+------+------------+
| id | page | new_column |
+--------+------+------------+
| 258126 | 22 | 5678772 |
| 258127 | 17 | 4388159 |
| 258128 | 20 | 5162560 |
| 258129 | 20 | 5162580 |
| 258130 | 17 | 4388210 |
+--------+------+------------+
*/

第十一章:使用数据处理函数

本章介绍函数

大多数SQL实现支持以下类型的函数。

  1. 用于处理文本串(如删除或填充值,转换值为大写或小写)的文本函数。
  2. 用于在数值数据上进行算术操作(如返回绝对值,进行代数运算) 的数值函数。
  3. 用于处理日期和时间值并从这些值中提取特定成分(例如,返回 两个日期之差,检查日期有效性等)的日期和时间函数。
  4. 返回DBMS正使用的特殊信息(如返回用户登录信息,检查版本细节)的系统函数。

文本处理函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
select categories,Upper(categories)as upper_categories from commic_list group by categories;
/*
+------------+------------------+
| categories | upper_categories |
+------------+------------------+
| doujinshi | DOUJINSHI |
| manga | MANGA |
+------------+------------------+
*/
select commic_url,left(right(commic_url,7),6) as url from commic_list limit 5;
/*
+-------------------------------+--------+
| commic_url | url |
+-------------------------------+--------+
| https://nhentai.net/g/258126/ | 258126 |
| https://nhentai.net/g/258127/ | 258127 |
| https://nhentai.net/g/258128/ | 258128 |
| https://nhentai.net/g/258129/ | 258129 |
| https://nhentai.net/g/258130/ | 258130 |
+-------------------------------+--------+
*/

常用的字符串函数:

1113510-20181226155910408-1414424975

1
2
3
4
5
6
7
8
9
10
11
12
13
select upload_time,
concat(mid(upload_time,9,4),'-','1','-',mid(upload_time,6,1)) as date from commic_list limit 5;
/*
+-------------------------+----------+
| upload_time | date |
+-------------------------+----------+
| Jan. 2, 2019, 1:53 a.m. | 2019-1-2 |
| Jan. 2, 2019, 1:54 a.m. | 2019-1-2 |
| Jan. 2, 2019, 1:58 a.m. | 2019-1-2 |
| Jan. 2, 2019, 1:59 a.m. | 2019-1-2 |
| Jan. 2, 2019, 2:02 a.m. | 2019-1-2 |
+-------------------------+----------+
*/

有一个很有意思的函数SOUNDEX:根据发音来检索.

1
2
3
4
5
# 查找一个Y.Lie的人,但是数据库里输错了,输成了Y.Lee
# 直接查找肯定是失败的
select name from table1 where name = 'Y.Lie' # return None
# 这时可以使用soundex函数
select name from table1 where Soundex(name) = Soundex('Y.Lie')

日期和时间处理函数

881554811480639

1
2
3
# order_date的类型是datetime(形如2019-01-01 11:30:05)
# 这时需要使用date函数将其转化为日期格式(2019-01-01)(就是去掉后面的时间)
select order_date from table1 where Date(order_date) = '2019-01-01'
1
2
3
4
5
6
# 匹配2019年9月的数据
select order_date from table1
where Date(order_date) between '2019-09-01' and '2019-9-30'
# 或者使用month,year,day函数
select order_date from table1
where year(order_date)='2019' and month(order_date)='9'

数值处理函数:

1554813110429

第十二章:汇总数据

本章介绍什么是SQL的聚集函数以及如何利用它们汇总表的数据。

汇总数据有以下几种:

  1. 确定表中行数(或者满足某个条件或包含某个特定值的行数)。
  2. 获得表中行组的和。
  3. 找出表列(或所有行或某些特定的行)的最大值、最小值和平均值。

聚集函数(aggregate function)常用只有五个:

函数 说明
AVG() 返回某列的平均值
COUNT() 返回某列的行数
MAX() 返回某列的最大值
MIN() 返回某列的最小值
SUM() 返回某列值之和
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
select avg(page) from commic_list where artists='yuzu'
/*
+-----------+
| avg(page) |
+-----------+
| 29.8430 |
+-----------+
*/
select count(artists) from commic_list where languages='english';
/*
+----------------+
| count(artists) |
+----------------+
| 46 |
+----------------+
*/

注意:avg(),min(),max(),sum()都忽略列值为NULL的行。 但是count需要分类讨论.

count函数需要着重注意:COUNT()函数有两种使用方式。

  1. 使用COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值。
  2. 使用COUNT(column)对特定列中具有值的行进行计数,忽略 NULL值。

也就是说,==如果指定列名,则指定列的值为空的行被COUNT() 函数忽略,但如果COUNT()函数中用的是星号(*),则不忽略==

1
2
3
4
5
6
7
8
9
# max函数允许对使用非数值类型的字段
select max(commic_url) from commic_list;
/*
+-------------------------------+
| max(commic_url) |
+-------------------------------+
| https://nhentai.net/g/258352/ |
+-------------------------------+
*/
1
select sum(id*page) from commic_list;

聚集不同值:
聚集函数的DISTINCT的使用

以上5个聚集函数都可以如下使用:

  1. 对所有的行执行计算,指定ALL参数或不给参数(因为ALL是默认行为);
  2. 只包含不同的值,指定DISTINCT参数。

(ALL参数不需要指定,因为它是默认行为。如果 不指定DISTINCT,则假定为ALL)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 简单来说就是先让page变成distinct了再求avg
# 类似于python的avg(set(page))和avg(page)的区别
select (distinct avg(page)) as new from commic_list;
/*
+---------+
| new |
+---------+
| 50.6182 |
+---------+
*/
select avg(page) as new from commic_list;
/*
+---------+
| new |
+---------+
| 29.8430 |
+---------+
*/

如果指定列名,则DISTINCT只能用于COUNT(),不能用于COUNT(*),因此不允许使用COUNT(DISTINCT), 否则会产生错误。类似地,DISTINCT必须使用列名,不能用 于计算或表达式

将DISTINCT用于MIN()和MAX() :
虽然DISTINCT从技术上可用于MIN()和MAX(),但这样做实际上没有价值。一个列中的最小值和最大值不管是否包含不同值都是相同的。

组合聚集函数
目前为止的所有聚集函数例子都只涉及单个函数。但实际上SELECT 语句可根据需要包含多个聚集函数

1
2
3
4
5
6
7
8
select min(page) as min,max(page) as max,avg(page) as avg from commic_list;
/*
+------+------+---------+
| min | max | avg |
+------+------+---------+
| 3 | 198 | 29.8430 |
+------+------+---------+
*/

第十三章:分组数据

本章将介绍如何分组数据,以便能汇总表内容的子集。这涉及两个新SELECT语句子句,分别是GROUP BY子句和HAVING子句。

一般来说,使用汇总数据的5个函数的时候是不可以select原字段的.因为这样根本不能形成一个表

1
2
# 下面代码是错的
select artists,avg(page) from commic_list;

这时就要使用group by来进行分组:

1
2
3
4
5
6
7
8
9
10
11
# 计算每个作者的平均页数
select artists,avg(page) from commic_list group by artists;
/*
+--------------+-----------+
| artists | avg(page) |
+--------------+-----------+
| ago | 34.0000 |
| aimaitei | 29.0000 |
| ajishio | 11.0000 |
+--------------+-----------+
*/

在具体使用GROUP BY子句前,需要知道一些重要的规定。

  1. GROUP BY子句可以包含任意数目的列。这使得能对分组进行嵌套, 为数据分组提供更细致的控制。
  2. 如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算 (所以不能从个别的列取回数据)。
  3. GROUP BY子句中列出的每个列都必须是检索列或有效的表达式 (但不能是聚集函数)。==如果在SELECT中使用表达式,则必须在 GROUP BY子句中指定相同的表达式==。不能使用别名。
  4. ==除聚集计算语句外,SELECT语句中的每个列都必须在GROUP BY子句中给出==。
  5. 如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。
  6. GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。

WITH ROLLUP:在group分组字段的基础上再进行统计数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 计算每种语言的平均页数
select languages,avg(page) from commic_list group by languages;
/*
+-----------+-----------+
| languages | avg(page) |
+-----------+-----------+
| chinese | 37.3333 |
| english | 30.0870 |
| japanese | 27.3130 |
| text | 13.0000 |
+-----------+-----------+
*/
select languages,avg(page) from commic_list group by languages with rollup;
/*
+-----------+-----------+
| languages | avg(page) |
+-----------+-----------+
| chinese | 37.3333 |
| english | 30.0870 |
| japanese | 27.3130 |
| text | 13.0000 |
| NULL | 29.8430 |
+-----------+-----------+
*/
# 上面的NULl其实就是对37.3333,30.0870,27.3130,13.0000再求一次平均值.

过滤分组:HAVING子句
除了能用GROUP BY分组数据外,MySQL还允许过滤分组,规定包括 哪些分组,排除哪些分组。
HAVING非常类似于WHERE。事实上,目前为止所 学过的所有类型的WHERE子句都可以用HAVING来替代。==唯一的差别是WHERE过滤行,而HAVING过滤分组==。
WHERE子句不起作用,因为过滤是基于分组聚集值而不是特定行值的。

1
2
3
# 查找总页数大于150的作者
select artists,sum(page) from commic_list
group by artists having sum(page) >150;

有另一种理解方法,WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。

那么有没有同时使用where和having呢?只要在分组前过滤,然后在分组后再过滤一遍即可.

1
2
3
4
5
6
# 查找作品的语言是英语,同时总页数大于60的作者
select artists,languages,sum(page)
from commic_list
where languages = 'english'
group by artists
having sum(page) > 60;

分组和排序
GROUP BY和ORDER BY的差别:

order by group by
排序产生的输出 分组行,但输出可能不是分组的顺序
任意列都可以使用(甚至非选择列都可以使用) 只能是选择列或表达式列,而且必须使用每个选择列表达式
不一定需要 如果与聚集函数一起使用列(或表达式),则必须使用

因为group by的顺序可能不是分组的顺序,所以有时候需要同时使用order by和group by

1
2
3
4
5
6
7
8
# 查找作品的语言是英语,同时总页数大于60的作者
# 然后按照总页数升序排列
select artists,languages,sum(page)
from commic_list
where languages = 'english'
group by artists
having sum(page) > 60
order by sum(page);

总结 SELECT子句顺序 :

子句 说明 是否必须使用
select 要返回的列或表达式
from 从中检索数据的表 仅在表中选择数据时使用
where 行级过滤
group by 分组说明 仅在按组计算聚集时使用
having 组级过滤
order by 输出排序顺序
limit 要检索的行数

第十四章:使用子查询

本章介绍什么是子查询以及如何使用它们。

迄今为止我们所看到的所有SELECT语句都是简单查询,即从单个数据库表中检索数据的单条语句。
子查询(subquery),即嵌套在其他查询中的查询。

1
2
select cust_id from orders where order_num in 
(select order_num from orderitems where prod_id = 'TNT2')

使用子查询可以看到:==外查询where的内容其实就是内查询select的内容==.这就是列匹配原则
子查询一般与IN操作符结合使用

作为计算字段使用子查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 计算less_table表中有,more_table表中也有的id总数
select count(id) from more_table
where id in (select id from less_table);
/*
+-----------+
| count(id) |
+-----------+
| 200 |
+-----------+
*/
# 注意不可以如下使用,要使用子查询
select id from more_table where less_table.id = more_table.id;
# 或者改成
select id from less_table,more_table where less_table.id = more_table.id;

==也就是说,where里用到的表在from一定要提到==

相关子查询(correlated subquery) 涉及外部查询的子查询。
任何时候只要列名可能有多义性,就必须使用这种语法(表名和列名由一个句点分隔)。