Mysql数据查询
Mysql查询
数据多次过滤
条件:from、where、group by、having、distinct、order by、limit => 层层筛选后的结果
查:
select [distinct] 字段1 [[as] 别名1],...,字段n [[as] 别名n] from [数据库名.]表名 [条件];
注:一条查询语句,可以拥有多种筛选条件,条件的顺序必须按照上方顺序进行逐步筛选,distinct稍有特殊(书写位置),条件的种类可以不全
可以缺失,但不能乱序
单表查询
distinct 去重
数据为:
+------+------+
| x | y |
+------+------+
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
| 1 | 2 |
+------+------+
#执行
select distinct * from t1;
+------+------+
| x | y |
+------+------+
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
+------+------+
# 总结:distinct对参与查询的所有字段,整体去重(所查的全部字段的值都相同,才认为是重复数据)
常用函数
拼接:concat() | concat_ws()
大小写:upper() | lower()
浮点型操作:ceil() | floor() | round()
整型:可以直接运算
concat()和concat_ws()
mysql>: select name as 姓名, concat(area,'-',port) 地址 from emp; # 上海-浦东
mysql>: select name as 姓名, concat_ws('-',area,port,dep) 信息 from emp; # 上海-浦东-教职部
#concat_ws(),可以在每个字段之间加上第一个字符
upper()和lower()
select upper(name) 姓名大写,lower(name) 姓名小写 from emp;
ceil(),floor(),round()
#元数据
+------+
| x |
+------+
| 1.5 |
| 1.2 |
| 1.51 |
+------+
#ceil() 向上取整
mysql> select ceil(x) from t2;
+---------+
| ceil(x) |
+---------+
| 2 |
| 2 |
| 2 |
+---------+
#floor()向下取整
mysql> select floor(x) from t2;
+----------+
| floor(x) |
+----------+
| 1 |
| 1 |
| 1 |
+----------+
#round() 特殊版本的四舍五入 5的时候舍
mysql> select round(x) from t2;
+----------+
| round(x) |
+----------+
| 2 |
| 1 |
| 2 |
+----------+
整数
select x+1 from t1;
where
常用判断
比较符合:> | < | >= | <= | = | !=
区间符合:between 开始 and 结束 | in(自定义容器) | not in
逻辑符合:and | or | not
相似符合:like _|%
正则符合:regexp 正则语法
自定义区间:id in (2,3) | id not in (2,3) | id < all(2,3) | id < any(2,3)
案例
mysql>: select * from emp where salary>5;
mysql>: select * from emp where id%2=0;
mysql>: select * from emp where salary between 6 and 9;
mysql>: select * from emp where id in(1, 3, 7, 20);
# _o 某o | __o 某某o | _o% 某o* (*是0~n个任意字符) | %o% *o*
mysql>: select * from emp where name like '%o%';
mysql>: select * from emp where name like '_o%';
mysql>: select * from emp where name like '___o%';
# sql只支持部分正则语法
mysql>: select * from emp where name regexp '.*\d'; # 不支持\d代表数字,认为\d就是普通字符串
mysql>: select * from emp where name regexp '.*[0-9]'; # 支持[]语法
all与any:区间修饰条件
# 语法规则
# where id in (1, 2, 3) => id是1或2或3
# where id not in (1, 2, 3) => id不是1,2,3
# where salary < all(3, 6, 9) => salary必须小于所有情况(小于最小)
# where salary > all(3, 6, 9) => salary必须大于所有情况(大于最大)
# where salary < any(3, 6, 9) => salary只要小于一种情况(小于最大)
# where salary > any(3, 6, 9) => salary只要大于一种情况(大于最小)
in < > ()
# 案例
select * from emp where salary < all(select salary from emp where id>11);
分组group by
分组与筛选:group by|having
where和having区别
1.where在分组之前限定,如果不满足条件,则不参与分组。
having在分组之后进行限定,如果不满足结果,则不会被查询出来
2.where后不可以跟聚合函数,having可以进行聚合函数的判断
聚合函数
max():最大值
min():最小值
avg():平均值
sum():和
count():记数
group_concat():组内字段拼接,用来查看组内其他字段
分组查询group by
配置
# 修改my.ini配置重启mysql服务
sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
注意
分组查询的字段只有:分组字段、聚合函数
having不能使用聚合函数别名
完整体
select sex,AVG(math),COUNT(id) from student where math>70 group by sex having count(id) > 2
实验
#元数据
+------+------+
| z1 | z2 |
+------+------+
| 1 | zx |
| 2 | zy |
| 9 | zx |
| 5 | zy |
| 6 | zx |
| 7 | zy |
+------+------+
#执行
select z2,avg(z1) from t3 group by z2;
+------+---------+
| z2 | avg(z1) |
+------+---------+
| zx | 5.3333 |
| zy | 4.6667 |
+------+---------+
联合分组
简单来说就是对多个字段分组
#执行
select z1,z2 from t3 group by z1,z2;
+------+------+
| z1 | z2 |
+------+------+
| 1 | zx |
| 2 | zy |
| 5 | zy |
| 6 | zx |
| 7 | zy |
| 9 | zx |
+------+------+
排序
排序规则
# order by 主排序字段 [asc|desc], 次排序字段1 [asc|desc], ...次排序字段n [asc|desc]
未分组状态下
mysql>: select * from emp;
# 按年龄升序
mysql>: select * from emp order by age asc;
# 按薪资降序
mysql>: select * from emp order by salary desc;
# 按薪资降序,如果相同,再按年龄降序
mysql>: select * from emp order by salary desc, age desc;
# 按龄降序,如果相同,再按薪资降序
mysql>: select * from emp order by age desc, salary desc;
分组状态下
mysql>:
select
dep 部门,
group_concat(name) 成员,
max(salary) 最高薪资,
min(salary) 最低薪资,
avg(salary) 平均薪资,
sum(salary) 总薪资,
count(gender) 人数
from emp group by dep;
# 最高薪资降序
mysql:
select
dep 部门,
group_concat(name) 成员,
max(salary) 最高薪资,
min(salary) 最低薪资,
avg(salary) 平均薪资,
sum(salary) 总薪资,
count(gender) 人数
from emp group by dep
order by 最高薪资 desc;
分页limit
# 语法:limit 条数 | limit 偏移量,条数
#元数据
+------+------+
| z1 | z2 |
+------+------+
| 1 | zx |
| 2 | zy |
| 9 | zx |
| 5 | zy |
| 6 | zx |
| 7 | zy |
+------+------+
#执行
select * from t3 limit 1;
+------+------+
| z1 | z2 |
+------+------+
| 1 | zx |
+------+------+
#执行
select * from t3 limit 2,2;
+------+------+
| z1 | z2 |
+------+------+
| 9 | zx |
| 5 | zy |
+------+------+
多表查询
分类
1.内连接
2.左连接
3.右连接
4.全连接
from 左表 inner|left|right join 右表 on 两个表之间的关联条件
inner:都是有用的
left:左边全有
right:右边全有
全连:left union right 有用没用都有
笛卡尔积
笛卡尔积是数据库多表连接的基础,它会列出所有的组合,多表查询其实就是对笛卡尔积进行过滤留下有用的数据
1 2 3和z x y的笛卡尔积
1 z 1 x 1 y
2 z 2 x 2 y
3 z 3 x 3 y
select * from z1,z2
一对一和一对多
元数据
+------+----------+
| id | name |
+------+----------+
| 1 | 教室_1 |
| 2 | 教室_2 |
| 3 | 教室_3 |
| 4 | NULL |
| NULL | NULL |
+------+----------+
+------+------+
| id | name |
+------+------+
| 1 | zx |
| 2 | wl |
| 3 | zy |
| 1 | zxy |
| 2 | fd |
| 3 | hj |
| 4 | ds |
| 1 | NULL |
| NULL | NULL |
+------+------+
内连接
找两张表共有的部分,相当于利用条件从笛卡尔积结果中筛选出了正确的结果
# 关键字:inner join on
# 语法:from A表 inner join B表 on A表.关联字段=B表.关联字段
可以简写为join
#执行
select * from class join student on class.id=student.id;
+------+----------+------+------+
| id | name | id | name |
+------+----------+------+------+
| 1 | 教室_1 | 1 | zx |
| 2 | 教室_2 | 2 | wl |
| 3 | 教室_3 | 3 | zy |
| 1 | 教室_1 | 1 | zxy |
| 2 | 教室_2 | 2 | fd |
| 3 | 教室_3 | 3 | hj |
| 4 | NULL | 4 | ds |
| 1 | 教室_1 | 1 | NULL |
+------+----------+------+------+
# 总结:只保留两个表有关联的数据
左连接
优先显示左表全部记录
# 关键字:left join on
# 语法:from 左表 left join 右表 on 左表.关联字段=右表.关联字段
#执行
select class.id,class.name,student.name from class left join student on class.id=student.id;
+------+----------+------+
| id | name | name |
+------+----------+------+
| 1 | 教室_1 | zx |
| 2 | 教室_2 | wl |
| 3 | 教室_3 | zy |
| 1 | 教室_1 | zxy |
| 2 | 教室_2 | fd |
| 3 | 教室_3 | hj |
| 4 | NULL | ds |
| 1 | 教室_1 | NULL |
| NULL | NULL | NULL |
+------+----------+------+
# 总结:保留左表的全部数据,右表有对应数据直接连表显示,没有对应关系空填充
右连接
优先显示右表全部记录
# 关键字:right join on
# 语法:from A表 right join B表 on A表.关联字段=B表关联字段
#执行
select class.id,student.name,class.name from class right join student on class.id=student.id;
+------+------+----------+
| id | name | name |
+------+------+----------+
| 1 | zx | 教室_1 |
| 1 | zxy | 教室_1 |
| 1 | NULL | 教室_1 |
| 2 | wl | 教室_2 |
| 2 | fd | 教室_2 |
| 3 | zy | 教室_3 |
| 3 | hj | 教室_3 |
| 4 | ds | NULL |
| NULL | NULL | NULL |
+------+------+----------+
# 总结:保留右表的全部数据,左表有对应数据直接连表显示,没有对应关系空填充
左右可以相互转化
更换一下左右表的位置,相对应更换左右连接关键字,结果相同
全连接
全外连接:在内连接的基础上增加左边有右边没有的和右边有左边没有的结果
#执行
select class.id,student.name,class.name from class left join student on class.id=student.id
UNION
select class.id,student.name,class.name from class right join student on class.id=student.id
order by id;
+------+------+----------+
| id | name | name |
+------+------+----------+
| NULL | NULL | NULL |
| 1 | zxy | 教室_1 |
| 1 | NULL | 教室_1 |
| 1 | zx | 教室_1 |
| 2 | fd | 教室_2 |
| 2 | wl | 教室_2 |
| 3 | hj | 教室_3 |
| 3 | zy | 教室_3 |
| 4 | ds | NULL |
+------+------+----------+
# 总结:左表右表数据都被保留,彼此有对应关系正常显示,彼此没有对应关系均空填充对方
# 注意 union与union all的区别:union会去掉相同的纪录
多对多
相当于在一对多的基础上,多建立一次连接
##源数据
#人物表
zx
+----+------+
| id | name |
+----+------+
| 1 | zx |
| 2 | wl |
| 3 | zy |
| 4 | zxy |
+----+------+
#关系表
zx_zy
+----+-------+-------+
| id | zx_id | zy_id |
+----+-------+-------+
| 1 | 1 | 1 |
| 2 | 1 | 3 |
| 3 | 2 | 2 |
| 4 | 2 | 4 |
| 5 | 3 | 1 |
| 6 | 3 | 3 |
| 7 | 4 | 5 |
| 8 | 4 | 2 |
| 9 | 4 | 3 |
+----+-------+-------+
#技能表
zy
+----+-----------+
| id | name |
+----+-----------+
| 1 | 吃饭 |
| 2 | 睡觉 |
| 3 | 打代码 |
| 4 | 写作业 |
| 5 | 上厕所 |
+----+-----------+
查询1
#执行
以关系表为中心,进行两次左连接
select zx_zy.id,zx.name,zy.name from zx_zy LEFT JOIN zx on zx.id=zx_zy.zx_id LEFT JOIN zy on zy.id=zx_zy.zy_id
+----+------+-----------+
| id | name | name |
+----+------+-----------+
| 1 | zx | 吃饭 |
| 2 | zx | 打代码 |
| 3 | wl | 睡觉 |
| 4 | wl | 写作业 |
| 5 | zy | 吃饭 |
| 6 | zy | 打代码 |
| 7 | zxy | 上厕所 |
| 8 | zxy | 睡觉 |
| 9 | zxy | 打代码 |
+----+------+-----------+
查询2
#执行
任意表,进行两次内连接
select zx_zy.id,zx.name,zy.name from zx join zx_zy on zx_zy.zx_id=zx.id join zy on zx_zy.zy_id=zy.id
+----+------+-----------+
| id | name | name |
+----+------+-----------+
| 1 | zx | 吃饭 |
| 2 | zx | 打代码 |
| 3 | wl | 睡觉 |
| 4 | wl | 写作业 |
| 5 | zy | 吃饭 |
| 6 | zy | 打代码 |
| 7 | zxy | 上厕所 |
| 8 | zxy | 睡觉 |
| 9 | zxy | 打代码 |
+----+------+-----------+
子查询
简单来说就是一个查询的数据当做另一个查询的查询条件
要注意的是子查询的数据一般有好多,一般用in
# 增:insert into 表 select子查询
# 删:delete from 表 条件是select子查询(表不能与delete表相同)
# 查:select 字段 from 表 条件是select子查询
# 改:update 表 set 字段=值 条件是select子查询(表不能与update表相同)
简单案例-子查询
##元数据
t1
+------+------+
| x | y |
+------+------+
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
| 1 | 2 |
+------+------+
t3
+------+------+
| z1 | z2 |
+------+------+
| 1 | zx |
| 2 | zy |
| 9 | zx |
| 5 | zy |
| 6 | zx |
| 7 | zy |
+------+------+
##需求根据t1的x,删除t3,与t1相同的z1数据
#执行
select * from t3;
+------+------+
| z1 | z2 |
+------+------+
| 9 | zx |
| 5 | zy |
| 6 | zx |
| 7 | zy |
+------+------+