三—02:Mysql02(DQL、SQL执行流程、多表)

一、DQL查询表中数据

DQL主要用于数据的查询,其基本结构是使用SELECT子句,FROM子句和WHERE子句的组合来查询一条或多条数据。

  • select

  • from

  • where

  • order by

  • having

  • 函数

  • group by

  • limit

1.简单查询

格式:select 字段名,字段名,... from 表名;

注意:

  1. 查询的所有字段可以用*代替。
  2. 查询部分字段,必须手动指定查询的字段。
  3. 查询的字段可以进行数字计算,函数操作...。
  4. 为字段定义别名,仅改变展示出来的字段名,数据库中的字段名不会改变。
select eid, ename, sex, salary, hire_date, dept_name from emp;

select * from emp;

select ename, salary from emp;

select ename, ename, salary from emp;




-- 定义别名,仅改变展示的名称
select eid, ename, sex, salary, hire_date, dept_name from emp;

select eid as '编号', ename as '姓名', sex as '性别', 
			salary as '薪资', hire_date as '入职日期', dept_name as '部门名称' from emp;

-- 定义别名简化,as可以省略不写
select eid '编号', ename '姓名', sex '性别', 
			salary '薪资', hire_date '入职日期', dept_name '部门名称' from emp;



-- 查询到的数据去重
   -- 将dept_name中查询到的值去除重
select distinct dept_name from emp;

select distinct dept_name '部门名称' from emp;


-- 查询到数据进行函数计算

select eid as '编号', ename as '姓名', sex as '性别', salary as '薪资',
			salary+1000 as '薪资', hire_date as '入职日期', dept_name as '部门名称' from emp;
select eid as '编号', ename as '姓名', sex as '性别', salary as '薪资',
			salary+1000 as '薪资', hire_date as '入职日期', dept_name as '部门名称' from emp;
select eid as '编号', ename as '姓名', sex as '性别', salary as '薪资',
			salary*12 as '年薪', hire_date as '入职日期', dept_name as '部门名称' from emp;

2.条件查询

2.1 条件查询(where)

格式:select 字段名,字段名,... from 表名  where  条件;

关键字: where

执行顺序:

  1.  从哪个表查询  from。
  2.  按照指定条件过滤 where。
  3. 指定返回的字段值 select。

条件:

  1. 比较:  > < >= <= != <>。
  2.  and ,&& 多个条件同时成立。
  3. between ... and ... 区间值(前后包含)。
  4.  or, ||  多个条件成立任意一个即可。
  5. in(值,值,...) 等于任意一个值即可。
  6. 值是否为null:is null  ,is not null。
-- 查询黄蓉的所有信息
select * from emp where ename = '黄蓉';
-- 查询黄蓉部分信息
-- 执行过程:1.从emp表中查询数据  2.where条件过滤  3.按照指定的字段返回
select eid, ename, salary from emp where ename = '黄蓉';


#2 查询薪水价格为5000的员工信息
select * from emp where salary = 5000;

#3 查询薪水价格不是5000的所有员工信息
select * from emp where salary != 5000;
select * from emp where salary <> 5000;

#4 查询薪水价格大于6000元的所有员工信息 
select * from emp where salary > 6000;

#5 查询薪水价格在5000到10000之间的员工信息 
select * from emp where salary>=5000 and salary<=10000;
select * from emp where salary>=5000 && salary<=10000;
select * from emp where salary between 5000 and 10000; -- 前后包含


#6 查询薪水价格是3600或7200或者20000的员工信息
select * from emp where salary=3600 or salary=7200 or salary=20000;
select * from emp where salary=3600 || salary=7200 || salary=20000;
select * from emp where salary in(3600, 7200, 20000); -- 等于任意一个即可


-- null的判断
select * from emp where salary is null;
select * from emp where dept_name is not null;

2.模糊查询

2.1 模糊(like)

格式: select 字段,字段,... from 表名 where 字段 like xxx;

关键字:like

模糊查询中的通配符:
            1.   %: 0~n个字符。
            2.    _: 1个字符。

#1 查询含有'八'字的员工信息
select * from emp where ename like '%八%';

#2 查询以'孙'字开头的员工信息 
select * from emp where ename like '孙%';

#3 查询第二个字为'兔'的员工信息 
select * from emp where ename like '_兔%';

3.排序(order by)

排序:将查询出的结果按照指定的要求排序。

关键字:order by 

1.单列排序:按照指定列中的值进行排序。
           格式: select 字段,字段,... from 表 [where 条件] order by 字段[desc];


2.多列排序:按照指定多个列中的值进行排序,先按照指定的第一个列中的值排序,出现重复再按照第二个列中的值排序,...
          格式:  select 字段,字段,... from 表 [where 条件] order by 字段[desc],字段[desc];

注:排序默认为升序,添加desc变为降序。

-- 查询所有教学部门的员工信息,薪资升序排列
select * from emp where dept_name='教学部' order by salary;  -- 默认使用升序
select * from emp where dept_name='教学部' order by salary asc; -- 手动指定为升序
select * from emp where dept_name='教学部' order by salary desc; -- 手动指定为降序


-- 先按照薪资降序,出现相同的薪资,再按照入职日期升序排序
select * from emp order by salary desc,hire_date;

4.函数

函数:方法。将具体的操作封装在方法中,调用方法来完成相关的操作。
函数分类:
1.单行函数:对一行中的数据进行操作,操作多少行返回多少行。

  • 字符串函数
  • 数值函数
  • 日期与时间函数
  • 流程控制函数
  • 其他函数

2.多行函数:对一列中的数据进行操作,最终返回一个结果。

4.1 单行函数 
4.1.1 字符串函数
-- 1.将字母转换为小写
select eid, ename, ename, sex, salary, hire_date, dept_name from emp;

select eid, ename, lower(ename), sex, salary, hire_date, dept_name from emp;

-- 2.将字母转换为大写
select eid, ename, upper(ename), sex, salary, hire_date, dept_name from emp;

-- 3.返回占用的字节数(utf-8编码中一个中文占用3个字节)
select eid, ename, length(ename), sex, salary, hire_date, dept_name from emp;

-- 4.字符串拼接
select eid, ename, sex, salary, hire_date, dept_name, concat(dept_name, ' 门') from emp;

-- 5.左侧填充
select eid, ename, lpad(ename, 5, 'a'), sex, salary, hire_date, dept_name from emp;

-- 6.右侧填充
select eid, ename, rpad(ename, 7, 'oxx'), sex, salary, hire_date, dept_name from emp;

-- 7.去除字符串左右空格
	-- 去除左空格
select eid, ename, ltrim(ename), sex, salary, hire_date, dept_name from emp;	
	-- 去除右空格
select eid, ename, rtrim(ename), sex, salary, hire_date, dept_name from emp;		
	-- 去除左右空格
select eid, ename, trim(ename), sex, salary, hire_date, dept_name from emp;	

-- 8.替换指定的字符
select eid, ename, replace(ename, "悟", "x"), sex, salary, hire_date, dept_name from emp;

-- 9.字符翻转
select eid, ename, reverse(ename), sex, salary, hire_date, dept_name from emp;

-- 10.字符串截取,从1开始
select eid, ename, substr(ename, 1, 2), substring(ename, 1, 2), sex, salary, hire_date, dept_name from emp;


insert into emp(ename) values(" abc "),(" b c d ")
#1 查询emp表所有数据, 将eid, ename, sex显示格式为 编号: x 姓名: xx 性别: x
select concat("编号:", eid), concat("姓名:", ename), concat("性别:", sex) from emp;

#2 查询emp表所有数据, 将ename第二个字符都换为 某
-- insert(1,2,3,4)  1:字符串 2:从那个开始 3:几个字符 4:替换的新字符
select eid, ename, insert(ename, 2, 2, "某某"), sex, salary, hire_date, dept_name from emp;

#3 查询emp表所有数据, ename只显示姓
select eid, substr(ename, 1, 1), sex, salary, hire_date, dept_name from emp;

select eid, concat(substr(ename, 1, 1), "某某"), sex, salary, hire_date, dept_name from emp;
4.1.2 数值函数

对数字进行操作。

select abs(1), abs(-2) from dual; -- dual虚表,例如直接操作值,值不属于某个表的字段,可以使用虚表。
-- 返回num的绝对值
select abs(1), abs(-2); -- dual虚表可以省略
-- 返回大于num的最小整数(向上取整),返回小于num的最大整数(向下取整),返回圆周率的值,返回num的n次方,返回0~1之间的随机数,返回x四舍五入后的值该值保留到小数点后n位,返回num被舍去至小数点后n位的值(与 ROUND 最大的区别是不会进行四舍五入)
select ceil(3.5), floor(3.5), mod(3,2), pi(), pow(2,3), rand(), round(1.245, 2), truncate(1.245,2);
4.1.3 日期函数
select curdate(), curtime(), now(), sysdate();
select year("2020-10-11"), month("2020-10-11"), day("2020-10-11");
4.1.4 流程控制函数
IF(condition, t, f)如果条件condition为真,则返回t,否则返回f
IFNULL(value1, value2)如果value1不为null,则返回value1,否则返回value2
NULLIF(value1, value2)如果value1等于value2,则返回null,否则返回value1
CASE WHEN [condition1] THEN result1 [WHEN [condition2] THEN result2 ...] [ELSE result] END如果条件condition1为真,则返回result1,···,否则返回result
#1 查询emp表所有数据, 薪资 >= 10000 高工资  其他 低工资
select eid, ename, sex, salary, hire_date, dept_name from emp;

select eid, ename, sex, salary, if(salary>=10000, "高工资", "低工资"), hire_date, dept_name from emp;

#2 查询emp表所有数据, 计算出员工的年薪 薪资*12 加年终奖(每人30k)
select eid, ename, sex, salary "月薪", salary*12 "年薪", hire_date, dept_name from emp;

select eid, ename, sex, salary "月薪", salary*12 "年薪", salary*12+30000 "年薪含年终奖", hire_date, dept_name from emp;

select eid, ename, sex, salary "月薪", salary*12 "年薪", ifnull(salary, 0)*12+30000 "年薪含年终奖", hire_date, dept_name from emp;

#3 查询emp表所有数据, 薪资 >=3000 加把劲  >=5000 加油哦  >=9000 坚持住 >= 15000 优秀  其他 不及格
select eid, ename, sex, salary, 
	case
		when salary>=15000 then "优秀"
		when salary>=9000 then "坚持住"
		when salary>=5000 then "加油哦"
		when salary>=3000 then "加把劲"
		else "不及格"
	end, hire_date, dept_name from emp;
4.1.5 其它函数
DATABASE()返回当前数据库名
VERSION()返回当前MySQL的版本号
USER()返回当前登录的用户名
INET_ATON(IP)返回IP地址的数字表示
INET_NTOA返回数字代表的IP地址
PASSWORD(str)实现对字符串str的加密操作
FORMAT(num, n)实现对数字num的格式化操作,保留n位小数
CONVERT(data, type)实现将数据data转换成type类型的操作
4.2 多行函数
  • 多行函数会忽略null空值。

  • 多行函数也称为分组函数, 聚合函数

count(字段)统计指定列不为null的记录行数
sum(字段)计算指定列的数值和
max(字段)计算指定列的最大值
min(字段)计算指定列的最小值
avg(字段)计算指定列的平均值
#1 查询员工的总数 
-- 使用某个字段查询,聚合函数会忽略null, 需要注意为null的字段
select count(eid) from emp;  
-- 所有字段匹配查询
select count(*) form emp; 
-- 增加一列
select 1 from emp;	
-- 效率更高推荐使用		  
select count(1) from emp;

#2 查看员工总薪水、最高薪水、最小薪水、薪水的平均值, 显示为总薪水, ... 
select 
	sum(salary) '总薪水',
	max(salary) '最高薪水',
	min(salary) '最小薪水',
	avg(salary) '平均薪水'
from emp;

#3 查询薪水大于4000员工的个数 
select count(1) from emp where salary > 4000;

#4 查询部门为'教学部'的所有员工的个数 
select count(1) from emp where dept_name = '教学部';

#5 查询部门为'市场部'所有员工的平均薪水
select avg(salary) from emp where dept_name = '市场部';

#6 查询部门的个数
select dept_name from emp;  -- 9个
select count(dept_name) from emp; -- 8个
-- 部门去重之后, 统计个数
select count(distinct dept_name) from emp; -- 3个
 4.3 面试题

5.分组(group by)

5.1 分组相关

分组查询指的是使用group不要语句。对查询的信息进行分组,相同数据作为一组。

语法格式:

select 分组字段/聚合函数 from  表名 group by  分组字段 [having 条件];

group by分组过程:

 5.2 注意事项

注意事项:

  • 分组时可以查询要分组的字段, 或者使用聚合函数进行统计操作。

  • 查询其他字段没有意义  。

  • 需要在分组后,对数据进行过滤,where的作用 是在分组前过滤。

  • select语句执行顺序:from --  where --- group by --having  -- select -- order  by。

  • 分组操作中的having子语句, 适用于对分组后的数据进行过滤的, 作用类似于where。

5.3 where和having的区别
过滤方式特点
where分组之前的过滤后边不能写多行函数
having分组之后的过滤后边可以写多行函数

 演示:

#1 统计每个部门中的最小工资, 列出最小工资小于4000的部门名称及最小薪资
-- 每个部门的最小工资
select dept_name, min(salary)  from emp group by dept_name; 
select dept_name, min(salary)  from emp group by dept_name having min(salary) < 4000;

#2 统计平均工资大于6000的部门名称 
-- 每个部门的平均工资
select dept_name, max(salary)  from emp group by dept_name;
select dept_name, max(salary)  from emp group by dept_name having max(salary) > 6000;

#3 统计人数小于4个人部门的平均工资
-- 每个部门的平均工资和人数
select dept_name, avg(salary), count(1) from emp group by dept_name;  
select dept_name, avg(salary), count(1) from emp group by dept_name having count(1) < 4;

#4 统计每个部门最高工资, 排除最高工资小于10000的部门
-- 每个部门的最高工资
select dept_name, max(salary) from emp group by dept_name
select dept_name, max(salary) from emp group by dept_name having max(salary) >= 10000;

6.limit关键字

作用:

  • limit是限制的意思, 限制返回的查询结果的函数(通过limit函数,控制查询返回多少行数据)。

  • limit 语法是 MySql的方言, 用来完成分页

语法格式:

select 字段1, 字段2 ... from 表名 limit offset, length;

参数说明

  1. offset 起始行数, 从0开始, 如果省略则默认从0开始, 0代表MySQL中第一条数据。

  2. length 返回的行数。

演示:

#1 查询emp表中的前5条数据
select * from emp limit 5;   -- 不指定从哪行还是, 默认从0开始
select * from emp limit 0, 5;

#2 查询emp表中 从第4条开始, 查询6条
select * from emp limit 3, 6; -- 从0开始, 所以第四条数据为3

二、SQL执行流程

1. SQL语句执行流程

1.1 执行流程图示

1.2 各个组件介绍

1.连接管理与安全验证:MySQL有连接池(Connection Pool)管理客户端的连接。客户端连接后会验证用户名、密码、主机信息等。

2.缓存(Cache&Buffer ):缓存中存储了SQL命令的HASH,直接比对SQL命令的HASH和缓存中key是否对应,如果对应,直接返回结果,不再执行其他操作。缓存里面包含表缓存、记录缓存、权限缓存等。

3.解析器:主要作用是解析SQL命令。将SQL命令分解成数据结构(解析树),后续的操作都是基于这个结构的。如果在分解过程中遇到错误,出现SQL解析错误。解析时主要检查SQL中关键字是否正确、SQL中关键字顺序是否正确、引号是否对应是否正确等。

4.预处理器:根据解析器的解析树,进一步检查表是否存在、列是否存在、名字和别名是否有歧义等。

5.优化器(Optimizer ):在执行SQL查询时会根据开销自动选择最优查询方案。采用“选择-投影-连接”的策略。先选择where中的行数。同时先选择要选择的列,而不是全部列,最后把内容合并到一起。

6.执行器:包含执行SQL命令。获取返回结果。生成执行计划等。

7.存储引擎:访问物理文件的媒介。

1.3 执行流程详细说明

1.客户端向服务器端发送SQL命令和连接参数。

2.服务器端连接模块连接并验证。

3.缓存模块解析SQL为Hash并与缓存中Hash表对应。如果有结果直接返回结果,如果没有对应继续向下执行。如果是MySQL 8 是没有查询缓存的。

4.解析器解析SQL为解析树,检查关键字相关问题,如果出现错误,报SQL解析错误。如果正确,继续执行。

5.预处理器对解析树继续处理检查表、列别名等,处理成功后生成新的解析树。

6.优化器根据开销自动选择最优执行计划,生成执行计划。

7.执行器执行执行计划,访问存储引擎接口。

8.存储引擎访问物理文件并返回结果。

9.如果开启查询缓存,缓存管理器把结果放入到查询缓存中。

10.返回结果给客户端。

三、多表

1.单表的缺点

冗余, 同一个字段出现大量重复的数据。

2.多表中的外键

2.1 表关系分析

  1. 员工表中有一个字段dep_id与部门表中的主键对应字段,这个字段就叫做关系属性。

  2. 拥有关系属性的员工表被称为从表, 与关系属性对应的主键所在的表叫做主表。

2.2 外键约束

外键:指的是在主表中与从表主键对应的的那个字段, 如员工表的dep_id, 就是外键。

外键约束 :使用外键约束可以让两张表之间产生一个对应关系, 从而保证主从表数据的完整性。

 2.3 创建外键约束

方式一:

create table emp(
	eid int primary key auto_increment,
	ename varchar(15),
	age int,
	did int,
	constraint emp_dept_fk foreign key(did) references dept(did)
);
desc emp;

方式二: 

create table emp(
	eid int primary key auto_increment,
	ename varchar(15),
	age int,
	did int
);
alter table emp add constraint e_d_fk foreign key(did) references dept(did);
2.4 删除外键约束

格式:alter table 从表名 drop foreign key 外键约束的名称;

alter table employee drop foreign key emp_dep_fk;
2.5 外键约束的注意事项

1.外键约束作用 

 1.操纵从表

  • 向从表中添加外检值时,添加的外检值必须在关联主表的主键值中存在。
  • 修改从表中外键值时,修改后的外键值必须在关联主表的主键值中存在。

 2.操纵主表

  • 删除主表中数据时,必须满足从表中的外键值在主表的主键值中存在。
  • 变更主表中主键值时,必须满足从表中的外键值在主表的主键值中存在。
/*
	外键约束:
		1.删除主表中数据时,必须满足从表中的外键值在主表的主键值中存在
		2.变更主键中主键值是,必须满足从表中的外键值在主表的主键值中存在
	
*/
# 方式一:
-- 1.手动删除从表中关联的数据
-- > Affected rows: 3
delete from emp where did=1;

-- 2.删除主表中的数据
-- > Affected rows: 1
delete from dept where did=1;

# 方式二:
-- 1.手动将从表中关联的外键值设置为null
-- > Affected rows: 3
update emp set did=null where did=2;
-- 2.删除主表中的数据
-- > Affected rows: 1
delete from dept where did=2;

2. 创建和删除表

  • 删除表时:先删除从表,再删除主表。
  • 创建表时:先创建主表,再创建从表。

3.外键约束设置

  • RESTRICT(默认)  和No action:如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作。
  • setNull:删除或更新主表中数据时,将关联从表中的外键值设置为null。
  • cascade:删除主表中数据时,将关联从表中的数据删除。更新主表中主键值时,将关联从表中的外键值变为新的主键值。

四、 多表查询

1.多表关系设计

表与表之间的3种关系举例
一对多关系(最常见)员工表和部门表 学生表和班级表
多对多关系学生表和课程表 用户表和角色表
一对一关系(使用较少)一对一的关系可以设计成一张表

2. 笛卡尔积

交叉连接(CROSS JOIN)是对两个或者多个表进行笛卡儿积操作,所谓笛卡儿积就是关系代数里的一个概念,表示两个表中的每一行数据任意组合的结果。

笛卡尔积不管是否匹配,都连接。没有实际意义,有理论意义 。笛卡尔积便于理解连接查询的原理。

语法格式:select 字段名 from 表1 cross join 表2; 

select * from products cross join category; 

 3.多表查询分类

3.1 内连接

通过条件匹配两张表中的数据,能匹配就显示,不能匹配就不显示。

 语法格式:

  • SQL92:select 字段名,.... from 表1,表2 where 条件;
  • SQL99:select  字段名,... from 表1 [inner] join 表2 where 条件;
3.1.1 等值内连接

判断条件为等值判断,等值内连接:
                            SQL92:select 字段,... from 表1,表2 where 字段1=字段2;
                            SQL99:select 字段,... from 表1 join 表2 on 字段1=字段2;

 不同表之间:

-- 只获取家电类别及产品信息
select * from category c,products p where c.cid=p.cid and c.cid='c001';
select * from category c  join products p on c.cid=p.cid where c.cid='c001';

-- 只获取家电类别及产品信息 排序
select * from category c,products p where c.cid=p.cid and c.cid='c001' order by price;
select * from category c  join products p on c.cid=p.cid where c.cid='c001' order by price;

-- 统计所有类别下产品的数量
select cname, count(1) from category c,products p where c.cid=p.cid group by cname;
select cname, count(1) from category c  join products p on c.cid=p.cid group by cname;

 同一张表(自连接):

-- 自连接
-- 查询所有的员工及员工的领导
-- 自连接的内连接
select e2.empno, e2.ename, e1.empno, e1.ename from emp1 e1, emp1 e2 where e1.empno = e2.mgr;
select e2.empno, e2.ename, e1.empno, e1.ename from emp1 e1 join emp1 e2 on e1.empno = e2.mgr;
3.1.2  非等值内连接

判断条件为非等值判断,非等值内连接:

  • SQL92:select 字段,... from 表1,表2 where 字段1 between 字段2 and 字段3;
  • SQL99:select 字段,... from 表1 join 表2 on 字段1 between 字段2 and 字段3;
-- 内连接,非等值连接
select * from emp1, salgrade where sal between losal and hisal;
select * from emp1 join salgrade on sal between losal and hisal;
3.2 外连接

通过指定的条件去匹配两张表中的数据, 匹配上就显示, 匹配不上也可以显示。

   3.2.1 左外连接

以左表为主,左表中的数据全部显示,右表没有匹配的数据以null填充。
                    select 字段,... from 表1 left [outter] join 表2 on 条件;

 非等值:

-- 左外连接,非等值连接
select * from emp1 left join salgrade on sal between losal and hisal;

等值:

select * from category c left outer join products p on c.cid=p.cid;
select * from category c left join products p on c.cid=p.cid;

 自连接:

-- 自连接的左外连接
select e1.empno, e1.ename, e2.empno, e2.ename from emp1 e1 left join emp1 e2 on e1.empno = e2.mgr;

 3.2.2 右外连接

以右表为主,右表中的数据全部显示,左表没有匹配的数据以null填充。
                    select 字段,... from 表1 right [outter] join 表2 on 条件;

  非等值:

select * from emp1 right join salgrade on sal between losal and hisal;

等值:

-- 左外连接:左表数据全部显示,右表没有匹配的数据以null填充111
select * from category c left outer join products p on c.cid=p.cid;
select * from category c left join products p on c.cid=p.cid;

 自连接:

-- 自连接的右外连接
select e1.empno, e1.ename, e2.empno, e2.ename from emp1 e1 right join emp1 e2 on e1.empno = e2.mgr;
3.2.3 全外连接

MySQL 中不支持 FULL OUTER JOIN 连接,可以使用 union 实现全完连接。

语法结构:(SELECT  列名 FROM 表名 LEFT OUTER JOIN  表名 ON  连接条件) 
UNION 
(SELECT  列名 FROM 表名 RIGHT OUTER JOIN  表名 ON  连接条件)。

select * from category c left join products p on c.cid=p.cid
union
select * from category c right join products p on c.cid=p.cid;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值