阶段四:MySQL8数据查询操作
数据查询语言(核心)
0、数据集准备
CREATE TABLE tb_product
(
pid INT PRIMARY KEY auto_increment, -- p==product,pid==产品id编号
pname VARCHAR(20), -- 产品名称
price DOUBLE, -- 产品价格
category_id VARCHAR(32) -- 产品所属分类编号(c001电子产品,c002服装)
) DEFAULT CHARSET=utf8mb4;插入数据:
INSERT INTO tb_product VALUES (1,'联想',5000,'c001');
INSERT INTO tb_product VALUES (2,'海尔',3000,'c001');
INSERT INTO tb_product VALUES (3,'雷神',5000,'c001');
INSERT INTO tb_product VALUES (4,'杰克琼斯',800,'c002');
INSERT INTO tb_product VALUES (5,'真维斯',200,'c002');
INSERT INTO tb_product VALUES (6,'花花公子',440,'c002');
INSERT INTO tb_product VALUES (7,'劲霸',2000,'c002');
INSERT INTO tb_product VALUES (8,'香奈儿',800,'c003');
INSERT INTO tb_product VALUES (9,'相宜本草',200,'c003');
INSERT INTO tb_product VALUES (10,'面霸',10,'c003');
INSERT INTO tb_product VALUES (11,'好想你枣',5,'c004');
INSERT INTO tb_product VALUES (12,'香飘飘奶茶',10,'c005');
INSERT INTO tb_product VALUES (13,'海澜之家',200,'c002');DataGrip软件关键字替换,可以使用Ctrl + R快捷键
1、select查询(核心)
# 根据某些条件从某个表中查询指定字段的内容
格式:select [distinct]*| 列名,列名 from 表 [where 条件]
select 查询哪些列多个列用逗号隔开 from 数据表 where 查询条件(满足条件的就显示,不满足的就忽略)2、简单查询
-- 1.查询所有的商品.
select * from tb_product;
-- 2.查询商品名和商品价格.
select pname, price from tb_product;
-- 3.查询结果是表达式(运算查询):将所有商品的价格+10元进行显示.
select pname, price+10 from tb_product;
-- 4.查询所有商品对应的商品分类信息(不能重复)
select distinct category_id from tb_product;3、五子句
SQL除了简单查询以外,还支持五子句查询(SQL查询五子句)
select */字段 from 数据表 ① where子句 ② group by子句 ③ having子句 ④ order by子句 ⑤ limit子句
① where:条件查询
② group by:分组查询
③ having:条件查询,只不过发生在分组之后,可以对分组后结果进行筛选
④ order by:排序子句,用于排序操作
⑤ limit:限制查询,用于限制查询数量
五子句可以单独出现,也可以多个关键词一起出现。但是不管多少个关键字都必须严格按照五子句顺序进行书写,否则报错!!!4、条件查询(where子句)
作用:五子句的一部分
select \* from 数据表 where子句 group by分组子句 having子句 order by子句 limit子句

☆ 比较查询
-- 查询商品名称为“花花公子”的商品所有信息:
SELECT * FROM tb_product WHERE pname = '花花公子';
-- 查询价格为800商品
SELECT * FROM tb_product WHERE price = 800;
-- 查询价格不是800的所有商品
SELECT * FROM tb_product WHERE price != 800;
SELECT * FROM tb_product WHERE price <> 800;
-- 查询商品价格大于60元的所有商品信息
SELECT * FROM tb_product WHERE price > 60;
-- 查询商品价格小于等于800元的所有商品信息
SELECT * FROM tb_product WHERE price <= 800;
SELECT * FROM tb_product WHERE price > 60 并且 price <= 800☆ 逻辑查询
逻辑上的与、或、非。其中,AND 与、OR 或、NOT 非。
-- 查询商品价格在200到1000之间所有商品
SELECT * FROM tb_product WHERE price >= 200 AND price <=1000;
-- 查询商品价格是200或800的所有商品
SELECT * FROM tb_product WHERE price = 200 OR price = 800 OR price = 1000;
-- 查询价格不是800的所有商品
SELECT * FROM tb_product WHERE NOT(price = 800);☆ 范围查询
语法:
范围查询:between 低 and 高,表示区间查询;
精确匹配:in (A, B, C) 表示=A、或=B、或=C的数据
-- 查询商品价格在200到1000之间所有商品
SELECT * FROM tb_product WHERE price BETWEEN 200 AND 1000;
-- 查询商品价格是200或800或1000的所有商品
SELECT * FROM tb_product WHERE price IN (200, 800, 1000);可以测试一下,BETWEEN 1000 AND 200,看看会是什么结果?
☆ 模糊查询
字段 like '匹配条件'
匹配条件有两个符号:%任意多个任意字符,\_只匹配任意某1个字符
-- 查询以'香'开头的所有商品
SELECT * FROM tb_product WHERE pname LIKE '香%';
-- 查询第二个字为'想'的所有商品
SELECT * FROM tb_product WHERE pname LIKE '_想%'; 好想、好想你、好想你枣☆ 空值查询 与 非空查询
where 字段=null(错误)
where 字段 is null(正确)
-- 查询没有分类的商品
select * from tb_product where category_id is null;
-- 查询有分类的商品
select * from tb_product where category_id is not null;5、简单查询的常见用法(扩展)
☆ case when
简单查询中,还可以使用 case when 子句,进行字段的替换,通常用来替换字典或离职员工名字。
-- 比如,把gender的'0', '1'转换成男女
create table tb_employee (
id int,
name varchar(32),
gender tinyint -- 男0,女1
);
insert into tb_employee
values (1, '张三', 0)
, (2, '晓红', 1)
, (3, '李四', 0)
;
select
name,
case gender when 0 then '男' else '女' end as '性别'
from tb_employee;应用场景
- 数据分类(如将数字转为文字描述)。
- 动态计算(如根据条件调整价格)。
- 行转列(如统计不同类型的数量)
【课下作业】
有一张表格,如下,
序号 姓名 学科 成绩
1 张三 语文 95
2 张三 数学 98
3 张三 英语 78
4 李明 语文 98
5 李明 数学 94
6 李明 英语 85
7 王冰 语文 86
8 王冰 数学 89
9 王冰 英语 85
请转换成如下格式,输出展示
姓名 语文 数学 英语
张三 95 98 78
李明 98 94 85
王冰 86 89 85
提示:
使用case when [else] end 语法进行处理;
部分内容涉及到下一章的知识点——聚合函数,可以搜索AI☆ left() 和 right()
LEFT(string, length):从字符串左侧开始,截取指定长度的字符
SELECT LEFT('HelloWorld', 5); -- 输出 "Hello"RIGHT(string, length):从字符串右侧开始,截取指定长度的字符
SELECT LEFT('HelloWorld', 5); -- 输出 "World"应用场景
- 提取固定长度前缀(如身份证前 6 位表示地区)。
- 截断超长字符串(如显示文章摘要)。
- 分隔路径(如 LEFT(file_path, LOCATE('/', file_path)-1))
☆ concat()
CONCAT() 是用于字符串拼接的核心函数,支持将多个字符串连接为一个。
SELECT CONCAT('a', 'b', 'c', 'd'); -- 输出 "abcd"
-- 若任一参数为 NULL,则结果为 NULL
SELECT CONCAT('Hello', NULL, 'World'); -- 输出 NULL☆ 汇总
本节内容
<sheet sheet-id="QkbQQF" token="KWsrssTeqh2geutpuRIcNv0VnXd"></sheet>
其他常用函数
<sheet sheet-id="tp61JY" token="KWsrssTeqh2geutpuRIcNv0VnXd"></sheet>
DQL数据查询(进阶)
0、聚合函数
前置知识点:as关键词,用于给 数据表 或 数据表中的字段 定义别名
-- 数据表定义别名
select
别名.A,
别名.B,
...
from
数据表 [as] 别名;
-- 比如
select
tb_record.id,
tb_record.name,
tb_record.age
from
db_itheima.tb_itheima_aiops_employee_record_log as tb_record;
-- 字段定义别名
select name, (chinese+english+math) [as] 别名 from 数据表; -- 这里得到语数外三科的总分
-- 比如
select name as '姓名', (chinese+english+math) as '总分' from tb_score;as 可加可不加,通常都会加上,增强可读性
作用:
之前我们做的查询都是横向查询,它们都是根据条件一行一行的进行判断。
而使用聚合函数查询是纵向查询,它是对一列的值进行计算,然后返回一个单一的值;
另外聚合函数会忽略空值。
聚合查询:
① 纵向查询(按列查询)
② 默认会忽略空值
今天我们学习如下五个聚合函数:
| 聚合函数 | 作用 |
|---|---|
| count() | 统计指定列不为NULL的记录行数; |
| sum() | 计算指定列的数值和,如果指定列类型不是数值类型,则计算结果为0 |
| max() | 计算指定列的最大值,如果指定列是字符串类型,使用字符串排序运算; |
| min() | 计算指定列的最小值,如果指定列是字符串类型,使用字符串排序运算; |
| avg() | 计算指定列的平均值,如果指定列类型不是数值类型,则计算结果为0 |
实现原理:

案例演示:
drop table if exists tb_score;
create table tb_score(
name varchar(32),
math int
);
insert into tb_score
values ('张三', 90),
('小明', 80),
('李四', 85),
('李辉', null);
-- 聚合函数
select count(math) from tb_score;1、分组查询(group by 子句)
作用:分组就是为了更好的进行数据的统计,分组 + 聚合。
按性别分组、按学科分组、按部门分组、按年级分组 => group by 分组字段A, 分组字段B(按这个字段进行划分分组)
光有分组一般没有特别的意义,但是有一个特性:去重(因为分组完,只展示一个,后面会演示)
面试过程中:
介绍一下,在SQL语句中,如何实现去重操作?
答:
我了解的一共有两种方式,distinct 或 group by
☆ 基本概念
分组查询就是将查询结果按照指定字段进行分组,字段中数据相等的分为一组。
分组查询基本的语法格式如下:GROUP BY 列名 [HAVING 条件表达式]
说明:
- 列名: 是指按照指定字段的值进行分组。
- HAVING 条件表达式: 用来过滤分组后的数据。
☆ group by
group by可用于单个字段分组,也可用于多个字段分组
-- 准备学生表students
create table students(
id int auto_increment, -- auto_increment 表示自增
name varchar(20),
age tinyint unsigned, -- 无符号小整型(或无符号微整型)
gender enum('male', 'female'),
score tinyint,
primary key(id) -- 这里单独一行声明主键,也是可以的
) default charset=utf8mb4;
show tables;
insert into students values (null, 'Tom', 23, 'male', 97); -- 会自动添加 id的
insert into students values (null, 'Jack', 24, 'male', 88);
insert into students values (null, 'Rose', 26, 'female', 99);
insert into students values (null, 'Eric', 27, 'male', 59);
insert into students values (null, 'Jennifer', 22, 'female', 76);
select * from students;
-- 根据gender字段来分组
select gender from students group by gender; -- 会发现输出结果去重了
-- 根据name和gender字段进行分组
select name, gender from students group by name, gender; -- 会发现输出结果去重了① group by可以实现去重操作
② group by的作用是为了实现分组统计(group by + 聚合函数)
☆ group by + 聚合函数的使用
-- 统计不同性别的人的平均年龄
select gender, avg(age) from students group by gender;
-- 统计不同性别的人的个数
select gender, count(*) from students group by gender;
-- 字符串聚合,了解即可
select category_id, group_concat(pname) from tb_product group by category_id;
group by使用注意事项:
select 分组字段, 聚合函数, 聚合函数 from students group by 分组字段;
SQL官方文档:在有group by出现的情况下,select后面的字段要么只能出现在分组中,要么只能出现在聚合函数中2、过滤(having 子句)
having作用和where类似都是过滤数据的,但是两者之间的执行顺序不同
① where子句(发生在分组之前)
② group by子句 (分组)
③ having子句(发生在分组之后)
☆ 第一种情况:如果只是简单的查询操作(没有group by的情况),大部分时间having是可以直接替代where子句
select * from tb_product where price > 800;以上语句等价于
select * from tb_product having price > 800;
☆ 第二种情况:
-- 根据gender字段进行分组,统计分组条数大于 2 的
select gender, count(*) from students group by gender having count(*) > 2;案例演示:
-- 1 统计各个分类商品的个数
select category_id, count(*) from tb_product group by category_id;
-- 2 统计各个分类商品的个数,且只显示个数大于 1 的信息
select category_id, count(*) from tb_product group by category_id having count(*) > 1;3、排序查询(order by 子句)
-- 通过order by语句,可以将查询出的结果进行排序。暂时放置在select语句的最后。
-- 格式:SELECT * FROM 表名 ORDER BY 排序字段 ASC|DESC;
ASC(Ascend /əˈsend/) 升序 (默认),默认情况下,ASC关键词可以省略不写
DESC (Descend /dɪˈsend/) 降序
-- 1.使用价格排序(降序)
select * from tb_product order by price desc;
-- 2.在价格排序(降序)的基础上,以品类排序(降序)
select * from tb_product order by price desc, category_id desc;
-- 首先按照第一个字段排序,如果第一个字段能比较出大小,则不需要进行字段2排序;
-- 如果第一个字段值相同,则系统会继续按照第二个字段进行排序4、分页(limit子句)
应用场景:① 限制查询 ② 分页查询
限制查询:主要限制数据查询的数量(获取数据表中的前3条数据)
select * from 数据表 limit 查询数量;
select * from 数据表 limit 偏移量(默认为0,类似索引下标),查询数量;
偏移量:索引下标,默认从0开始
0 第一条记录
1 第二条记录
2 第三条记录
-- 基本语法1:select * from 数据表 limit 查询数量;
-- 案例1:查询学生表中,成绩最高的学生信息(只查1个)
select * from students order by score desc limit 0, 1; -- 从0开始,只查一个
-- 等价于
select * from students order by score desc limit 1; -- 只查一个
-- 缺点说明:如果一个学生表有多个同学成绩相同,可能会导致,只能查出1名同学。
-- 基本语法2:select * from 数据表 limit 偏移量(从哪查默认为0,类似索引下标),查询数量;
-- 案例2:查询学生表中,成绩第2高(第2名)的学生信息
select * from students order by score desc limit 1, 1; -- 因为下标从 0 计算,所以这里 1 表示第二个分页查询:实际特别接近,因为只要有分页的地方,底层100%都是使用limit子句实现的

分页查询在项目开发中常见,由于数据量很大,显示屏长度有限,因此对数据需要采取分页显示方式。例如数据共有30条,每页显示5条,第一页显示1-5条,第二页显示6-10条。

格式:
SELECT 字段1,字段2... FROM 表名 LIMIT M,N
M: 整数,表示从第几条索引开始,计算方式 (当前页-1)* 每页显示条数
N: 整数,表示查询多少条数据
SELECT 字段1,字段2... FROM 表明 LIMIT 0,5
SELECT 字段1,字段2... FROM 表明 LIMIT 5,5总结
SQL查询五子句分别为:(where子句)、(group by子句)、(having子句)、(order by子句)、(limit子句)
----------------------------------------------------------------------
条件查询:select *|字段名 form 表名 where 条件;
聚合查询函数:count(),sum(),max(),min(),avg(),了解 group_concat()。
分组查询:SELECT 字段1,字段2… FROM 表名 GROUP BY 分组字段 HAVING 分组条件;
排序查询:SELECT * FROM 表名 ORDER BY 排序字段 ASC|DESC;
分页查询:
SELECT 字段1,字段2... FROM 表名 LIMIT M,N
M: 整数,表示从第几条索引开始,计算方式 (当前页-1)*每页显示条数
N: 整数,表示查询多少条数据多表查询(重点)
0、表与表之间的关系
在SQL语句中,数据表与数据表之间,如果存在关系,一般一共有3种情况:
① 1:1,一对一关系(高级)
比如有A、B两张表,A表中的每一条数据,在B表中有一条唯一的数据与之对应。
用户表 tb_user
| user_id(用户编号) | 账号username | 密码password |
|---|---|---|
| 001 | admin | admin888 |
| 002 | itheima | 123456 |
用户详情表 tb_user_items
| user_id(用户编号) | 真实姓名 | 年龄 | 联系方式 |
|---|---|---|---|
| 001 | 张三 | 16 | 10086 |
| 002 | 李四 | 18 | 10010 |
其中,user_id是一一对应的
我们把用户表与用户详情表之间的关系就称之为一对一关系。
② 1:N,一对多关系(重点)
比如有A、B两张表,A表中的每一条数据,在B表中都有多条数据与之对应,我们把这种关系就称之为一对多关系
产品分类表
| 分类id编号 | 分类名称 |
|---|---|
| 1 | 手机 |
| 2 | 电脑 |
产品信息表
| 产品id编号 | 产品名称 | 产品价格 | 所属分类id编号 |
|---|---|---|---|
| 1 | Apple iPhone 13 | 6799.00 | 1 |
| 2 | Redmi Note 9 | 3499.00 | 1 |
我们把产品分类表与产品表之间的(分类id的对应)关系就称之为一对多关系。
③ M:N,多对多关系(高级)
用户表
| 用户编号 | 登录账号 | 登录密码 |
|---|---|---|
| 1 | admin | admin888 |
| 2 | itheima | 123456 |
权限表
| 权限id编号 | 权限名称 |
|---|---|
| 1 | 增加 |
| 2 | 删除 |
| 3 | 修改 |
| 4 | 查询 |
虽然从以上图解来看,两者之间好像没有任何联系,但是两者之间其实是有关系的。
这种关系需要通过一张临时表进行呈现。
每个用户,应该有对应的权限,admin账号可以做增删改查,itheima账号可以做查询
反过来
每个权限都应该对应多个用户,查询权限 => admin/itheima
注意:如果两张表之间的关联关系为多对多关系,则必须建立一个中间表,在中间表中体现两者的关系。
中间表 :用户_权限表

1、交叉连接(笛卡尔积)
准备数据集:
-- 1. 准备数据集
-- 数据表classes,拥有两个字段,cls_id代表班级编号,cls_name代表班级名称
use db_itheima;
drop table classes;
create table classes(
cls_id int,
cls_name varchar(20)
) default charset=utf8mb4;
-- 插入数据,ui、java、python
insert into classes values
(1, 'UI'),
(2, 'Java'),
(3, 'Python');
-- 数据表students,拥有id、name、age、gender值使用male和female、score、cls_id
drop table students;
create table students(
id int,
name varchar(20),
age int,
gender enum('male', 'female'),
score decimal(11,2),
cls_id int
) default charset=utf8mb4;
-- 插入数据,刘备属于Java,貂蝉属于UI,赵云属于Python,关羽属于Python,大乔属于UI
insert into students values
(1, '刘备', 18, 'male', 100.00, 2),
(2, '貂蝉', 18, 'female', 99.00, 1),
(3, '赵云', 18, 'male', 98.00, 3),
(4, '关羽', 18, 'male', 96.00, 3),
(5, '大乔', 18, 'female', 97.00, 1);
-- 交叉连接也称之为笛卡尔积连接
select * from students cross join classes;
-- 或
select * from students, classes;
没有意义,但是它是所有连接的基础。其功能就是将表1和表2中的每一条数据进行连接。
结果:
字段数 = 表1字段 + 表2的字段
记录数 = 表1中的总数量 \* 表2中的总数量(笛卡尔积)
select * from classes; -- 单独查看
select * from students; -- 单独查看
☆ 关于笛卡尔
笛卡尔 —— 我思故我在

笛卡尔在解析几何的贡献
相传,有一天,笛卡尔生病卧床,病情很重,尽管如此他还反复思考一个问题:几何图形是直观的,而代数方程是比较抽象的,能不能把几何图形和代数方程结合起来,也就是说能不能用几何图形来表示方程呢?
突然,他看见屋顶角上的一只蜘蛛,拉着丝垂了下来。一会功夫,蜘蛛又顺这丝爬上去,在上边左右拉丝。蜘蛛的“表演”使笛卡尔的思路豁然开朗。他想,可以把蜘蛛看作一个点。他在屋子里可以上,下,左,右运动。
如果把地面上的墙角作为起点,把交出来的三条线作为三根数轴,那么空间中任意一点的位置就可以在这三根数轴上找到有顺序的三个数。
由此引出了直角坐标系的概念。因此,直角坐标系,又称为笛卡尔坐标系。
2、连接查询的介绍
连接查询可以实现多个表的查询,当查询的字段数据来自不同的表就可以使用连接查询来完成。
连接查询可以分为:
1. 内连接查询(也是默认连接) 2. 左外连接查询 3. 右外连接查询 4. 自连接查询(自己查询自己)
☆ 内连接(inner join)
查询两个表中符合条件的共有记录

内连接查询语法格式: inner join ... on 关联条件
select 字段 from 表1 inner join 表2 on 表1.字段1 = 表2.字段2;
-- 进行适当缩进和换行
select
字段
from
表1
inner join 表2 on 表1.字段1 = 表2.字段2;说明:
- inner join 就是内连接查询关键字
- on 就是连接查询条件
例1:使用内连接查询学生表与班级表,查询每个学生对应的具体班级信息。
-- 案例:求每个学生所属的班级信息(学生所有字段 + 班级名称)
select *
from
students
inner join classes
on students.cls_id = classes.cls_id;
-- 内连接基础上可以筛选想要的字段
select
students.*
, classes.cls_name
from
students
inner join classes
on students.cls_id = classes.cls_id;
-- 引入表别名机制,数据表名称 [as] 别名
select
s.name
, s.age
, s.gender
, c.cls_name
from students s
inner join classes c
on s.cls_id = c.cls_id;
-- 通过 换行+缩进 提升可读性,inner join on 还可以简写为 join on
select
s.name
, s.age
, s.gender
, c.cls_name
from
students as s
join classes as c -- join 默认就是 inner join
on s.cls_id = c.cls_id;小结
- 内连接使用inner join .. on .., on 表示两个表的连接查询条件
- 内连接根据连接查询条件取出两个表的 “交集”,也就是满足关联条件的结果。
- 特别注意:join 默认就是 inner join。
☆ 左外连接(left join)
有一个主表概念,默认情况下,关联后会保留主表的所有记录。
以左表为主根据条件查询右表数据,如果根据条件查询右表数据不存在,使用null值填充
商品分类表
| 编号 | 分类名称 |
|---|---|
| 1 | 手机 |
| 2 | 电脑 |
商品表
| 编号 | 商品名称 | 商品分类编号 |
|---|---|---|
| 1 | Vivo手机 | 1 |
| 2 | Xiaomi手机 | 1 |
左外连接查询:select \* from 分类表(主表) left join 商品表 on 分类表.编号 = 商品表.分类编号;
| 编号 | 分类名称 | 编号 | 商品名称 | 商品分类编号 |
|---|---|---|---|---|
| 1 | 手机 | 1 | Vivo手机 | 1 |
| 1 | 手机 | 2 | Xiaomi手机 | 1 |
| 2 | 电脑 | null | null | null |
左外连接默认会保留左表,然后与右边的表进行匹配;如果匹配到,则显示右表对应的数据;匹配不到,也要显示。只不过右表的所有字段使用null进行填充!

左连接查询语法格式:
select
字段
from
表1
left join 表2
on 表1.字段1 = 表2.字段2说明:
- left join 就是左连接查询关键字
- on 就是连接查询条件
- 表1 是左表
- 表2 是右表
例1:使用左连接查询学生表与班级表,获取每一学生对应的班级信息,要求没有对应的班级也要显示。
-- 使用左连接查询学生表与班级表,获取每一学生对应的班级信息,要求没有对应的班级也要显示。
insert into students values (6, '曹操', 30, 'male', 98, 9);
-- 左连接
select
s.*
, c.cls_name
from
students s
left join classes c on s.cls_id = c.cls_id;
小结
- 左连接使用left join .. on .., on 表示两个表的连接查询条件
- 左连接以左表为主根据条件查询右表数据,右表数据不存在使用null值填充。
☆ 右外连接(right join)
以右表为主根据条件查询左表数据,如果根据条件查询左表数据不存在则使用null值填充

右连接查询语法格式:
select
字段
from
表1
right join 表2(主表) on 表1.字段1 = 表2.字段2 -- 右连接
select *
from 表2
left join 表1说明:
- right join 就是右连接查询关键字
- on 就是连接查询条件
- 表1 是左表
- 表2 是右表
例1:使用右连接查询学生表与班级表:
-- 查看班级中对应的学生信息,如果某个班级没有对应的学生也要显示。(既可以用左外连接也可以用右外连接)
select
s.*
, c.cls_name
from
students s
right join classes c on s.cls_id = c.cls_id;
select
s.*
, c.cls_name
from
classes c
right join students s on c.cls_id = s.cls_id;

小结
- 右连接使用right join .. on .., on 表示两个表的连接查询条件
- 右连接以右表为主根据条件查询左表数据,
- 左表数据不存在使用null值填充;
- 左表数据存在右表不存在就不展示;
- 注意:左和右是相对的,如果两个表互换,左右也会反转
☆ 自连接查询(了解)
自连接查询:数据表自己连接自己,本质只有1张数据表,表内部数据有层级关系,比如,地区字典表。
前提:连接操作时必须为数据表定义别名!
左表和右表是同一个表,根据连接查询条件查询两个表中的数据。
两个实际的工作场景:求省市区信息,求分类导航信息
① 省份表 + 城市表 + 区域表(理论,实际设计表的过程中,通常只有1张数据表)
② 大类 + 中类 + 小类(理论,实际设计表的过程中,通常只有1张数据表)
---
地域:title
pid 全称 parent id(父级ID编号),如果pid值为null代表本身就是父级,如果pid是一个具体的数值,则代表其属于子级

例1:查询省的名称为“广东省”的所有城市
创建areas表:
use db_itheima;
create table areas (
aid int not null AUTO_INCREMENT,
atitle varchar(20),
pid int,
primary key (aid)
);执行sql文件给areas表导入数据:
insert into areas
values (1, '广东省', null),
(2, '山西省', null),
(3, '深圳市', 1 ),
(4, '广州市', 1 ),
(5, '太原市', 2 ),
(6, '大同市', 2 ),
(7, '河南省', null),
(8, '郑州市',7),
(9, '洛阳市', 7);
自连接查询的用法:
-- 第一步:把两张表关联查询(内连接)
select *
from
areas p
inner join areas c on p.aid = c.pid;
-- 第二步:在以上查询基础上,获取省份名称为广东省
select *
from
areas p
inner join areas c on p.aid = c.pid
where p.atitle = '广东省';
-- 第三步:只显示城市信息
select
c.atitle
from
areas p
inner join areas c on p.aid = c.pid
where p.atitle = '广东省';说明:
- 自连接查询必须对表起别名
小结
- 自连接查询就是把一张表模拟成左右两张表,然后进行连表查询。
- 自连接就是一种特殊的连接方式,连接的表还是本身这张表
总结
<sheet sheet-id="Wf5vyB" token="KWsrssTeqh2geutpuRIcNv0VnXd"></sheet>
3、子查询(扩展)
☆ 子查询(嵌套查询)的介绍
在一个 select 语句中,嵌入了另外一个 select 语句, 那么被嵌入的 select 语句称之为子查询语句。
外部那个select语句则称为主查询语句。
select \* from (select \* from xxx) as t;
作用:子查询比较适合复杂查询以及多层级查询结构。
主查询和子查询的关系:
1. 子查询是嵌入到主查询中 2. 子查询是辅助主查询的,要么充当条件,要么充当数据源(数据表) => 要么出现在where,要么出现在from位置 3. 子查询是可以独立存在的语句,是一条完整的 select 语句
了解:子查询的应用场景
答:在我们需求的基础上,如果这个需求需要通过多条SQL语句分步查询的情况,一般都需要基于子查询。
注:子查询会全表扫描两次,大数据量下需谨慎使用。所以我们说了解就行。
总结
子查询是一个完整的SQL语句,子查询被嵌入到一对小括号里面,子查询可以充当条件,也可以充当数据表使用。
掌握子查询编写三步走:
① 编写子查询
② 编写主查询并融合伪代码
③ 伪代码替换为子查询
子查询会全表扫描两次,大数据量下需谨慎使用。
同步说明
本文由飞书云文档同步生成。涉及命令、SQL、配置示例时,请以飞书源文档和实际环境执行结果为准。