当前位置: 首页 > news >正文

MySql复习知识及扩展内容

DDL操作库和表

-- todo ------------操作库----------------------------------
-- 创建库
create database if not exists day10 charset utf8;
create database if not exists day11 char set gbk;
-- 使用库
use day10;
-- 查询库
show databases ;
-- 删除库
drop database day11;
​
-- todo ------------操作表----------------------------------
-- 创建表-- 知道表结构:分析业务得到:设计一个存储学生信息的表.
/*学号   --(列) (字段)姓名年龄手机号性别籍贯生日
*/
create table student (id int primary key auto_increment,name varchar(20),age int,phone varchar(20),gender varchar(10),address varchar(20),birthday date
);
​
-- 查询表
show tables ;
-- 查询表的字段,类型,约束
desc student ;
-- 查询建表语句
show create table student;
​
​
-- 修改表
-- 修改表的列--添加列 -- 添加入学日期
alter table student add join_date date ;
-- 修改表的列--删除列
alter table student drop join_date;
-- 修改表的列--修改列的类型
alter table student modify name varchar(10);
-- 修改表的列--修改列的约束 -- name不能为空
alter table student modify name varchar(10) not null;
-- 修改表的列--修改列名 gender -sex
alter table student change gender sex varchar(10);
-- 修改表名  student--> stu
rename table student to stu;
​
-- 删除表
drop table stu;

DML操作数据

-- todo ------------操作数据 增删改----------------------------------
-- 添加一条数要求全列值插入.
insert into stu values (1,'tom',19,'17799889988','男','北京','1999-09-09');
-- 有主键自增的情况下可以主键可以给null值.实际上存储的是自增长的值.
insert into stu values (null,'jerry',18,'17799889966','男','北京','1999-09-10');
​
-- 添加一条数据.要求 只插入前3列
insert into stu (id, name, age) values (null,'rose',18);
​
-- 一次添加2条数据到表中.
insert into stu values (null,'张三',18,'17799889911','男','北京','1999-09-10'),(null,'李四',18,'17799889922','男','北京','1999-09-10');
-- ------------------------------------------------------------------
-- rose性别改为女
update stu set sex = '女' where name = 'rose';
​
-- 删除rose这个记录
delete from stu where name = 'rose';
​
-- 修改所有人的地址是上海
update stu set address = '上海';

DQL单表查询

create table product(pid int primary key auto_increment,pname varchar(20),price double,category_id varchar(20)
);
​
insert into product values
(1, '联想', 5000, 'c001'),
(2, '海尔', 3000, 'c001'),
(3, '雷神', 5000, 'c001'),
(4,'杰克琼斯',800, 'c002'),
(5, '真维斯', 200,'c002'),
(6,'花花公子',440,'c002'),
(7,'劲霸',2000,'c002'),
(8,'香奈儿',800,'c003'),
(9,'相宜本草',200,'c003'),
(10,'面霸',5,'c003'),
(11,'好想你枣',56,'c004'),
(12,'香飘飘奶茶',1,'c005'),
(13,'海澜之家',1000,'c002');
基本查询
#### 基本查询
select * from product;-- 查询所有记录的所有列.
select pid,pname,price  from product;-- 指定列查询
select distinct price, pname from product;-- 两个列联合去重
select distinct category_id from product; -- 查询商品不同的分类
条件查询
#### 条件查询  > < >= <= != <>
select * from product where pid > 3;
-- 查询分类为c001的商品
select * from product where category_id = 'c001';
范围查询
#### 范围查询
-- 连续的范围 -- 查询价格在500-800之间的商品
select * from product where price between 500 and 800;
select * from product where price >=500 and price <= 800;
​
-- 非连续的范围 --查询pid是c001和c003商品
select * from product where category_id in ('c001','c003');
select * from product where category_id= 'c001' or category_id= 'c003';
模糊查询
#### 模糊查询
/**列 like 符号 (% 和 _)%:表示0或者多个任意字符_:表示一个任意字符*/
-- 需求:查询商品名字包含香的.
select * from product where pname like '%香%';
-- 需求:查询商品名字以香开头的商品.
select * from product where pname like '香%';
-- 需求:查询商品名字以香开头的并且名字是3个字的.
select * from product where pname like '香__';
非空查询
#### 非空查询
-- 查询价格不是空的商品
select * from product where price is not null;
​
-- 查询价格是空的商品
select * from product where price is null;
select * from product where price = null;
排序查询
#### 排序查询
-- 按照价格升序排序
select * from product order by price;
select * from product order by price asc;-- 默认是asc
​
-- 按照价格降序排序
select * from product order by price desc;
​
-- 多字段排序 todo 第一排序字段内容一致此时第二排序字段才会生效.
-- 先按照价格降序排序.在按照id降序排序
select * from product order by price desc , pid desc ;
聚合查询
#### 聚合函数查询 max,min,avg,sum,count
select max(price) from product;
select min(price) from product;
select max(price),min(price),avg(price) from product;
​
select avg(price) from product where  pid >= 10;-- todo avg遇到null值会忽略该条记录.参数平均值的人就会少一个.
​
# sum 是求和 对单列的值进行累加
select sum(price) from product where pid >= 10;-- sum遇到null值会当做0来计算.
#count 是求记录数.(统计有几条记录)
select count(price) from product where pid >= 10;-- todo count遇到null会忽略该条数据.
select count(*) from product where pid >= 10;-- 会参考所有的列.只要有一个列不是null 就会统计.
select count(pid) from product where pid >= 10;-- 主键不会为null
select count(1) from product where pid >= 10;-- 有一条记录无论列是什么值都会统计该条记录.
分页查询
#### 分页查询  limit [m],n  (m起始点[默认0],n是个数)
​
-- 查询第一页的数据.每页展示5条.
select * from product limit 0,5;
​
-- 查询前3条记录
select * from product limit 3;-- 省略了m值.默认是0
​
-- 查询第3页的数据.每页展示5条. m的值需要计算 > 公式: (当前页码-1) * 每页展示个数  ==> (3-1) * 5 = 10
select * from product limit 10,5;
分组查询
#### 分组查询 group by [having 过滤条件]
/**分组思想:1.确定要分组的列.(按照什么来分) (一般不要按照主键分组)2.分组后你想干什么...2.1聚合统计计算 (聚合函数)2.2去重查询*/
-- 不同价格的商品有几个
select price, count(1) from product group by price;
-- 不同分类的商品中那个商品最贵.
select category_id,max(price) from product group by category_id;
-- 查询有几个分类
select distinct category_id from product; -- distinct去重
select category_id from product group by category_id; -- group by 去重
​
-- -- 不同价格的商品个数大于1的有哪些?
select price, count(1) ct from product group by price having ct > 1;
# select price, count(1) ct from product where ct > 1 group by price ; -- where 只能对表中的列进行过滤.

DQL多表关联查询

部门表: 部门编号,部门名称,部门位置
员工表: 员工编号,员工姓名,员工年龄,所属部门
-- todo ------------查询数据 多表查询----------------------------------
# 部门表: 部门编号,部门名称,部门位置
create table dept (id int primary key auto_increment,dname varchar(20),addr varchar(30)
);
​
# 员工表: 员工编号,员工姓名,员工年龄,所属部门
create table emp(id int primary key auto_increment,ename varchar(20),age int,dept_id int,foreign key (dept_id) references dept(id)
);
​
-- 插入数据;
insert into dept values (null,'财务部','上海'),(null,'人事部','北京'),(null,'研发部','北京');
insert into emp values (null,'张三',25,1),(null,'李四',25,2),(null,'王五',25,2),(null,'赵六',25,null);
交叉连接(笛卡尔积)

两个表相乘.

##### 交叉连接(笛卡尔积)
select * from dept cross join emp;
select * from dept , emp;
内连接
##### 内连接 -- 查询的是两个表的交集.
select * from dept d inner join emp e on d.id = e.dept_id;
​
-- 此时没有员工的部门和没有部门的员工都不能查出.

左连接
##### 左连接  -- 左表的全部和左右内俩接的结果
select * from dept d left join emp e on d.id = e.dept_id;
-- 此时员工表中没有部门的员工不能出现.

右连接
##### 右连接 -- 右表的全部和右内俩接的结果
select * from dept d right join emp e on d.id = e.dept_id;
​
-- 此时部门表中没有员工的部门信息不能出现.

DQL子查询

子查询的结果是1个值(单行单列)
子查询的结果是多个值(多行单列)
子查询的结果是一个表(多行多列)
子查询也叫嵌套查询,把一个大的问题拆分成为多个小的问题,小问题解决了大问题也随之解决.
-- todo  子查询 ----------------------------------
##### 子查询的结果是1个值(单行单列)
-- 查询价格最高的产品名字
select max(price)
from product; -- 5000
select *
from product
where price = (select max(price) from product);
​
##### 子查询的结果是多个值(多行单列)
-- 查询财务部和人事部的所有员工.
select id
from dept
where dname in ('财务部', '人事部');
select *
from emp
where dept_id in (select id from dept where dname in ('财务部', '人事部'));
​
​
##### 子查询的结果是一个表(多行多列)
-- 高于员工平均年龄的员工和部门信息.
select *
from emp
where age > (select avg(age) from emp);
​
select *
from dept djoin (select * from emp where age > (select avg(age) from emp)) e on d.id = e.dept_id;

DQL 自关联查询

案例1:

-- 创建一个地区表
CREATE TABLE areas(id VARCHAR(30) NOT NULL PRIMARY KEY, -- 地区IDtitle VARCHAR(30), -- 地区名称pid VARCHAR(30) -- 地区的上级地区的ID
);
insert into areas
values (1, '河南省', null),(2, '郑州', 1),(3, '洛阳', 1),(4, '新乡', 1);
-- 示例1:查询'河南省'下的所有市的信息
​
select a1.title, a2.title
from areas a1join areas a2 on a1.id = a2.pid;

案例2:

-- 【自关联扩展:自关联的妙用】
CREATE TABLE sales (month INT NOT NULL, -- 月份revenue DECIMAL(10, 2) -- 销售额
);
​
INSERT INTO sales
VALUES(1, 1000),(2, 800),(3, 1200),(4, 2000),(5, 1800),(6, 5000),(7, 3000),(8, 2500),(9, 1600),(10, 2200),(11, 900),(12, 4600);
​
-- 示例1:查询每个月的销售额和前一个月的销售额的差值
-- 查询结果字段:
--  月份、当前月销售额、前一个月销售额,当前月销售额和前一个月销售额的差
​
SELECTA.month, -- 月份A.revenue, -- 当月销售额B.revenue, -- 上个月销售额-- 计算当前销售额和上个月销售额的差值A.revenue - B.revenue AS `difference`
FROM sales A
JOIN sales B
ON A.month=B.month+1;
​
-- 示例2:查询截止到每个月的销售额。
-- 查询结果字段:
-- 月份,截止当前的累计销售额
​
SELECTA.month,SUM(B.revenue) AS `revenue`
FROM sales A
JOIN sales B
ON A.month >= B.month
GROUP BY A.month;

DQL窗口函数

create table employee
(dname    varchar(20), -- 部门名eid      varchar(20),ename    varchar(20),hiredate date,        -- 入职日期salary   double       -- 薪资
);
insert into employee
values ('研发部', '1001', '刘备', '2021-11-01', 3000);
insert into employee
values ('研发部', '1002', '关羽', '2021-11-02', 5000);
insert into employee
values ('研发部', '1003', '张飞', '2021-11-03', 7000);
insert into employee
values ('研发部', '1004', '赵云', '2021-11-04', 7000);
insert into employee
values ('研发部', '1005', '马超', '2021-11-05', 4000);
insert into employee
values ('研发部', '1006', '黄忠', '2021-11-06', 4000);
​
insert into employee
values ('销售部', '1007', '曹操', '2021-11-01', 2000);
insert into employee
values ('销售部', '1008', '许褚', '2021-11-02', 3000);
insert into employee
values ('销售部', '1009', '典韦', '2021-11-03', 5000);
insert into employee
values ('销售部', '1010', '张辽', '2021-11-04', 6000);
insert into employee
values ('销售部', '1011', '徐晃', '2021-11-05', 9000);
insert into employee
values ('销售部', '1012', '曹洪', '2021-11-06', 6000);
序号函数

rank(),row_number(),denserank()

-- 需求: 部门分组后按照薪资排序
select*,rank() over (partition by dname order by salary) rn
from employee;
-- 需求: 求出每个部门薪资排在前三名的员工- 分组求TOPN [重点]
select * from (select*,rank() over (partition by dname order by salary) rnfrom employee) t1where t1.rn <= 3;
聚合函数

sum(),count(),avg(),max(),nin()

#### 聚合函数
# sum(),count(),avg(),max(),nin()
select*,sum(salary) over () c1,count(1) over () c2,avg(salary) over () c3,max(salary) over () c4,min(salary) over () c5
from employee;
​
select*,sum(salary) over (partition by dname) c1,count(1) over (partition by dname) c2,avg(salary) over (partition by dname) c3,max(salary) over (partition by dname) c4,min(salary) over (partition by dname) c5
from employee;
​
-- 显示每个人的工资和平均工资
selectename,salary,avg(salary) over () c1
from employee;
前后函数

lag(),lead()

#### 前后函数
# lag(),lead()
select*,lag(hiredate,1,'未找到') over (partition by dname order by hiredate) lg,lead(hiredate,1,'未找到') over (partition by dname order by hiredate) ld
from employee;
​
# 需求1 : 按照部门分组,列出员工薪资和比他薪资靠前的一名员工的薪资.找不到就显示'已是最高薪资'
select * ,lag(salary,1,'已是最高薪资') over (partition by dname order by salary desc ) lg
from employee;
头尾函数

first_value(),last_value()

#### 头尾函数
# first_value(),last_value()
select *,first_value(hiredate) over (partition by dname ) f1,last_value(hiredate) over (partition by dname ) f2
from employee;
​
-- 需求1 : 统计各部门全部数据.按照日期排序查询第1个入职和最后1个入职员工的薪资
select *,first_value(salary) over (partition by dname order by hiredate rows between unbounded preceding and  unbounded following) f1,last_value(salary) over (partition by dname order by hiredate rows between unbounded preceding and  unbounded following) l1
from employee;
其它函数

nth_value(), ntile()

# #### 其它函数
# nth_value(), ntile()
select *,nth_value(salary,3) over (partition by dname) nthfrom employee;
​
-- ntile(5) 把窗口内的数据分为5个等份,不同的等份之间差值为1
select *,ntile(5) over () nthfrom employee;
​
-- 需求1 :查询每个部门截止目前薪资排在第二和第三的员工信息
select *,nth_value(salary,2) over (partition by dname order by salary desc rows between unbounded preceding and current row ) nth1,nth_value(salary,3) over (partition by dname order by salary desc rows between unbounded preceding and current row) nth2
from employee;
​
-- 需求2 :ntile()根据入职日期将每个部门的员工分成3组 .
select *,ntile(3) over (partition by dname order by hiredate) nt
from employee;
​
​
-- 需求3 :获取每组的第一份数据.抽样查询
with t1 as ( select *,ntile(3) over (partition by dname order by hiredate) nt
from employee )
select * from t1 where t1.nt = 1;

扩展知识

知识点1:窗口函数-自定义 window frame【掌握】

CREATE TABLE `tb_sales` (`month` int(2) NOT NULL,`sales` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `tb_sales` VALUES (1,10),(2,23),(3,14),(4,5),(5,32),(6,22),(7,52),(8,12),(9,19),(10,36),(11,33),(12,69);

思考题

现有一张某年度的月销量信息表 tb_sales,数据如下:

如何计算截止到每个月的累计销量?1月:1月销量,2月:1月销量+2月销量,3月:1月销量+2月销量+3月销量,依次类推

分区数据范围和window frame数据范围

在使用窗口函数处理表中的每行数据时,每行数据关联的数据有两种:

1)每行数据关联的分区数据

  • OVER()中什么都不写时,整张表默认是一个分区

  • OVER(PARTITION BY 列名, ...):整张表按照指定的列被进行了分区

2)每行数据关联的window frame数据

  • 每行关联的window frame数据范围 <= 每行关联的分区数据范围

  • window frame数据范围是分区数据范围的子集

目前我们所学的窗口函数中,有些窗口函数作用在分区上,有些函数作用在window frame上:

  • 聚合函数(SUM、AVG、COUNT、MAX、MIN)作用于每行关联的window frame数据上

  • 排名函数(RANK、DENSE_RANK、ROW_NUMBER)作用于每行关联的分区数据上

自定义 window frame 范围

自定义 window frame 范围有两种方式: ROWSRANGE

SELECT字段,...,<window function> OVER (PARTITION BY 列名, ...ORDER BY 列名, ...[ROWS|RANGE] BETWEEN 上限 AND 下限)
FROM 表名;
  • PARTITION BY 列名, ...:按照指定的列,对整张表的数据进行分区

  • ORDER BY 列名, ...:按照指定的列,对每个分区内的数据进行排序

  • [ROWS|RANGE] BETWEEN 上限 AND 下限:在排序之后的分区数据内,设置每行关联的window frame数据范围

上限和下限的设置

  • UNBOUNDED PRECEDING:对上限无限制

  • PRECEDING: 当前行之前的 n 行 ( n 表示具体数字如:5 PRECEDING

  • CURRENT ROW:仅当前行

  • FOLLOWING:当前行之后的 n 行 ( n 表示具体数字如:5 FOLLOWING

  • UNBOUNDED FOLLOWING:对下限无限制

  • 注意:上限需要在下限之前,比如:ROWS BETWEEN CURRENT ROW AND UNBOUNDED PRECEDING 是错误的

-- 需求:计算截止到每个月的累计销量。1月:1月销量,2月:1月销量+2月销量,3月:1月销量+2月销量+3月销量,依次类推
SELECTmonth,sales,SUM(sales) OVER(# 按照 month 对每个分区(注:此处就一个分区->整张表)数据进行排序ORDER BY month# 指定每行关联分区的 window frame 范围# UNBOUNDED PRECEDING:上限不限制# CURRENT ROW:当前行ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS `running_total`
FROM tb_sales;

window frame定义的简略写法

自定义 window frame 的边界时,如果使用了CURRENT ROW作为上边界或者下边界,可以使用如下简略写法:

  • ROWS UNBOUNDED PRECEDING 等价于 BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

  • ROWS n PRECEDING 等价于 BETWEEN n PRECEDING AND CURRENT ROW

  • ROWS CURRENT ROW 等价于 BETWEEN CURRENT ROW AND CURRENT ROW

  • 注意,简略写法不适合FOLLOWING的情况

ROWS和RANGE的区别

ROWS和RANGE关键字,都可以用来自定义 windowframe 范围:

ROWS BETWEEN 上限 AND 下限
RANGE BETWEEN 上限 AND 下限

但两者区别如下:

  • ROWS是根据分区数据排序之后,每一行的 row_number 确定每行关联的 window frame 范围的

    CURRENT ROW:仅代表当前行
    ​
    
    # 假设某一行数据的 row_number 为5,ROWS自定义window frame如下:
    ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING
    # 则这一行关联的window frame是:5-2 <= row_number <= 5+2 的数据

  • RANGE是根据分区数据排序之后,每一行的排序列的值确实每行关联的 window frame 范围的

    CURRENT ROW: 代表和当前行排序列的值相同的所有行
    ​
    
    # 假设某一行排序列的值为5,RNAGE自定义window frame如下:
    RANGE BETWEEN 2 PRECEDING AND 2 FOLLOWING
    # 则这一行关联的window frame是:5-2 <= 排序列的值 <= 5+2 的数据

默认的window frame

在 OVER 中只要添加了 ORDER BY,在没有写ROWS或RANGE的情况下,会有一个默认的 window frame范围:

  • RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

insert into tb_sales values (4,5),(4,10);-- 加入重复的月份
​
-- 需求:计算截止到每个月的累计销量。1月:1月销量,2月:1月销量+2月销量,3月:1月销量+2月销量+3月销量,依次类推
SELECTmonth,sales,SUM(sales) OVER(# 按照 month 对每个分区(注:此处就一个分区->整张表)数据进行排序ORDER BY month# OVER 中添加了 ORDER BY 之后,默认的 window frame 范围# RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS `running_total`
FROM tb_sales;

知识点2:SQL语句的执行顺序

SQL语句的执行顺序如下

FROM > JOIN > ON > WHERE > GROUP BY > 聚合函数 > HAVING > 窗口函数 > SELECT > DISTINCT > ORDER BY > LIMIT

1) FROM
2) JOIN
3) ON
4) WHERE
5) GROUP BY
6) 聚合函数
7) HAVING
8) 窗口函数
9) SELECT
10) DISTINCT【去重】
11) ORDER BY
12) LIMIT
-------------------------------------------------------------------------
SELECT ⑨[DISTINCT] 字段, ⑩...,聚合函数(字段), ⑥窗口函数 ⑧
FROM 表1 ①
JOIN 表2 ②
ON 关联条件 ③
WHERE 条件 ④
GROUP BY 分组字段, ... ⑤
HAVING 条件 ⑦
ORDER BY 排序字段, ... ⑪
LIMIT M, N; ⑫

知识点3:行转列

-- 创建 score 学生成绩表
CREATE TABLE score
(`学号` VARCHAR(24),`科目` VARCHAR(24),`成绩` INT
);
​
-- 给 score 表添加测试表
INSERT INTO score
VALUES ('s001', '语文', 90),('s001', '数学', 100),('s001', '英语', 93),('s002', '语文', 98),('s002', '数学', 99),('s002', '英语', 96);
​
SELECT * FROM score;
-- 科目 行转列
SELECT 学号,min(CASE when 科目 = '语文' THEN 成绩 END) '语文',min(CASE when 科目 = '数学' THEN 成绩 END) '数学',min(CASE when 科目 = '英语' THEN 成绩 END) '英语'
FROM score GROUP BY 1;

知识点4:列转行

-- 快速建表,并插入数据
CREATE table score2
SELECT 学号,min(CASE when 科目 = '语文' THEN 成绩 END) '语文',min(CASE when 科目 = '数学' THEN 成绩 END) '数学',min(CASE when 科目 = '英语' THEN 成绩 END) '英语'
FROM score GROUP BY 1;​
-- 列转行
-- UNION合并:奇技淫巧
SELECT  学号,'语文' as '科目',语文 as '成绩' FROM score2 -- 语文
union
SELECT  学号,'数学' as '科目',数学 as '成绩' FROM score2 -- 数学
union
SELECT  学号,'英语' as '科目',英语 as '成绩' FROM score2;-- 英语
​
​

http://www.mrgr.cn/news/45515.html

相关文章:

  • C语言从头学65—学习头文件 <stdio.h>(一)
  • 碧桂园服务携手安徽砀山,以购代捐助力乡村振兴
  • scaling 的作用
  • Python Kivy 完整应用开发:待办事项列表
  • 【RTCP】Interarrival Jitter: 到达间隔抖动的举例说明
  • 【Transformer 模型中的投影层,lora_projection是否需要?】
  • 点餐小程序实战教程17角色管理
  • OpenHarmony(鸿蒙南向开发)——轻量系统内核(LiteOS-M)【内存调测】
  • Ngx+Lua+Redis 快速存储POST数据
  • 如何使用PSTools工具集中的PSExec修改注册表信息,解决某些注册表项无法删除的问题
  • 以下是一些数据看板的常见使用场景:
  • 招个测试员,我又面试了100+人,未果…
  • 如何在VScode中加入系统安装好的python环境
  • Unity 从零开始的框架搭建1-1 unity中对象调用的三种方式的优缺点分析【干货】
  • PCL 计算法向量(MLS)
  • git commit失败整理
  • FLINK SQL
  • 修改Docker的默认存储路径
  • 个人常用的正则表达式匹配,以及实际应用
  • 【react】开发常用hooks统计