Python学习 -- MySQL数据库的查询及案例
数据库的查询
简单查询
# 语法
select 字段 from 表名;
字段* 代表查询全部字段名 代表查询指定字段字段名 别名 代表查询指定字段,以别名输出distinct 字段 代表查询指定字段并去重
#1 查询所有员工所有信息
select * from emp;
#2 查询全部员工姓名和工资
select ename,sal from emp;
#3 查询所有员工的姓名、薪资,追加别名
select ename 别名,sal 别名 from emp;
#4 查询所有职位,并去重
select distinct job from emp;
限定查询
在查询时限定某些特定的条件
# 语法
select 字段 from 表名 [限定语法];
限定语法where 条件(> >= < <= !=/<> or and in(元组) between...and... ...)
#1 查询薪资不等于3000的
select * from emp where sal <> 3000;
#2 查询薪资大于2000,小于5000的
select * from emp where sal > 2000 and sal < 5000;
select * from emp where sal between 2000 and 5000;
#3 查询多张表的薪资大于1000的,为表追加别名
select * from emp e where e.sal > 2000;
#4 查询名称中包含 S 的员工信息
select * from emp where ename like '%s%'; # like %s% 表示包含s的数据,通配符 % 代表匹配所有
#5 查询名称中第二个子母是 M 的员工信息
select * from emp where ename like '_m%'; # like _m% 表示包含s的数据,通配符 _ 代表匹配一个
#6 查询入职日期是 1981 的员工信息
select * from emp where hiredate like '1981%';
select * from emp where hiredate between '1981-01-01' and '1981-12-31';
排序查询
将查询后的结果作升降序排列,如果需要对多个字段进行排序,直接在排序条件后追加即可
# 语法
select 字段 from 表名 [限定语法] [排序语法];
排序语法关键字 order by 条件 asc(升序) desc(降序)
#1 按照入职日期做降序排列
select * from emp order by hiredate desc;
#2 按照薪资做升序排列
select * from emp order by sal asc;
#3 多个限定条件:按照入职日期做降序排列,如果日期相同那么根据薪资做升序排列
select * from emp order by hiredate desc,sal asc;
多表查询
如果我们要从多个表中查询数据呢,要简单的将两张表堆积在一起吗?
select * from dept,emp;
这样会带来数据冗余问题,出现多个重复数据,这种现象称之为笛卡尔效应。
# 语法
# 当两张表有关联字段时,可以通过关联字段联合查询
select 字段 from 表名1 ,表名2 where 表1_id = 表2_id;
#1 查询所有员工的员工编号、姓名、薪资、部门编号、部门名称
select e.empno 员工编号,e.ename 员工姓名,e.sal 薪资,e.deptno 部门编号,d.dname 部门名称 from emp e,dept d where e,deptno = d.deptno;
#2 查询所有员工编号、员工姓名、员工薪资、领导编号、领导姓名、领导薪资
逐步分析:
# Step.1 确定需要用到的表
emp e1,emp e2
# Step.2 确定需要用到的字段
e1.empno 员工编号,e1.ename 员工姓名,e1.sal 员工薪资,e2.empno 领导编号,e2.ename 领导姓名,e2.sal 领导薪资
# Step.3 确定需要用到的关联条件
e1.mgr = e2.empno
# Step.4 组装SQL
select e1.empno 员工编号,e1.ename 员工姓名,e1.sal 员工薪资,e2.empno 领导编号,e2.ename 领导姓名,e2.sal 领导薪资 from emp e1,emp e2 where e1.mgr = e2.empno;# 结果发现上述查询会少一个数据,即大领导没有上司就不会满足条件,怎么办?这就需要用到后面的连接查询
所以当进行多表联接时,为了避免产生笛卡尔积,至少需要N-1个联结条件(N为表数量)
- 两表关联:需要1个条件。
- 三表关联:在前两个表的基础上,第三个表需要1个新增条件,共需2个条件。
- 依此类推,每增加一个表需新增1个条件。因此,关联n个表至少需要n-1个条件。
连接查询
# 语法:
select 字段 from 表名 [连接条件][限定语法][排序条件]
# 连接条件 向哪加入哪当主表,主表数据不会丢失,当主表中的某行在另一个表中没有匹配行时,则该行显示为空值(NULL);如果表之间有匹配行,则整个结果集行包含主表的数据值。# 左(外)连接 左边当主表left (outer) join ... on ...# 右(外)连接 右边当主表right (outer) join ... on ...# 全连接 两边都是主表 (MySQL不支持)full join ... on ...# 内连接 全部都不是主表,只检索两个表中匹配的行(inner) join ... on ...
#1 所以上面的例子我们可以这么优化:
select e1.empno 员工编号,e1.ename 员工姓名,e1.sal 员工薪资,e2.empno 领导编号,e2.ename 领导姓名,e2.sal 领导薪资 from emp e1 left join emp e2 on e1.mgr = e2.empno;
全连接会先执行 left join 遍历左表,再执行 right join 遍历右表,最后将 right join 的结果直接追加到 left join 后面。注意,full join 会返回重复的行,它们会被保留,不会被删除。
连接语法来自于 SQL99 语法,这是1999年提出的,同时还有交叉连接(cross join)、自然连接(natural join)等,其中自然连接可以自动将两张表的相同字段提取出来放在前面,相当于自动实现多表查询
join 表 on 关联条件
join 表 using (关联字段)
分组查询
当需要分组的字段中出现了重复数据,可以使用分组查询查询有多少种类及其数量
# 语法:
select 分组字段/统计函数 from 表名 [连接条件][限定语法][分组查询][排序条件]
# 分组查询group by 分组字段
# 统计函数count(字段) 统计某一字段数量avg(字段) 统计某一字段平均值max(字段) 统计某一字段最大值min(字段) 统计某一字段最小值sum(字段) 统计某一字段的和
注意事项:
1. 一旦出现分组,那么 select 后面只允许出现分组字段及统计函数
2. 统计函数可以单独使用
3. 如果出现统计函数嵌套,那么在 select 后面只允许出现统计函数
4. 分组后如果还要使用条件判断,不允许使用 where,而是改为使用 having
#1 查询公司所有职位
select job,count(empno) from emp group by job; # 这里的分组字段是job,一般不会用count(*)扫描全表,而是用本表中的id来统计
#2 查询每个工作的平均工资
select job,count(empno),avg(sal) from emp group by job;
#3 查询每个工作的平均工资
select emp.job,count(empno),avg(sal),dept.dname from emp left join dept on emp.deptno = dept.deptno group by emp.job;
#4 查询平均工资高于2000的工作
select emp.job,count(empno),avg(sal),dept.dname from emp left join dept on emp.deptno = dept.deptno group by emp.job having avg(emp.sal) > 2000;
子查询
在查询中嵌套查询
# 语法
# 类型一 where子查询
# 当要查询的结果为单行单列或多行单列时
select 字段 from 表名 [where (子查询)];
# 类型二 from子查询
# 当需要将查询出来的表作为一个新表参与查询时
select 字段 from 表名,(子查询);
#1 查询比SMITH工资高的员工(单行单列)
select * from emp where sal > (select sal from emp where ename = "smith");
#2 查询与销售一样薪资的员工信息(多行单列)
select * from emp where sal in (select sal from emp where job = "SALESMAN");
#3
select * from emp where sal > (select avg(sal) from emp);
any 关键字
> any() 大于括号中的最小值
< any() 小于括号里的最大值
= any() 等同于 in
all关键字
> all() 大于括号中的最大值
< all() 小于括号里的最小值
= all() ???
查询部门编号、部门名称、部门位置、部门人数、平均薪资的信息
逐步分析:
# Step.1 确定需要的表格
dept d,emp e
# Step.2 确定需要关联的条件
d.deptno = e.deptno
# Step.3 确定需要的字段
d.deptno,d.dname,d.loc,count(e.empno),avg(e.sal)
# Step.4 确定需要的分组条件
group by e.deptno
# Step.5 组装SQL
select d.deptno,d.dname,d.loc,count(e.empno),avg(e.sal) from dept d left join emp e on d.deptno = e.deptno group by e.deptno;# 或者使用from子查询
select d.deptno,d.dname,d.loc,ifnull(temp.num,0),ifnull(temp.sal,0) from dept d left join
(select d.deptno,d.dname,d.loc,count(e.empno),avg(e.sal) from dept d , emp e where d.deptno = e.deptno group by e.deptno
)
temp on d.deptno = e.deptno;
分页查询
为什么需要分页 性能 页面
# 语法:
select 字段 from 表名 [连接条件][限定语法][分组查询][排序条件][分页查询];
分页查询关键字 limit n,m n下标索引,m每页显示条数n 默认值为0,可以省略不写,默认给出首页数据
#1 查询前十条员工信息
select * from emp limit 0,10;
select * from emp limit 10;
案例一 创建菜单表,分一级菜单和二级菜单
# 自关联操作
create table t_menu(id int(5) AUTO_INCREMENT,name varchar(10),image varchar(20),url varchar(20),pid int(5),constraint pk_id primary key(id),constraint fk_pid foreign key(pid) references t_menu(id)
) # 原理:二级菜单项的pid关联一级菜单项的id,可以通过子菜单(二级菜单)的pid找到其父菜单(一级菜单)
案例二 权限管理:用户登录
# 找到当前登录的用户的功能列表
# 本案例中数据表使用之前创建的5张权限管理表
select m.mid,m.mname,m.url from t_person p left join t_person_role pr on p.pid = pr.pid left join t_role r on pr.rid = r.rid left join t_role_menu rm on r.rid = rm.rid left join t_menu m on rm.mid = m.mid;