查询关键字 多表查询及练习题 可视化软件navicat

day 48

 

查询关键字之having过滤

having与where的功能是一模一样的 都是对数据进行筛选

两者差异:

where having
用于过滤数据行 用于过滤分组
在查询条件中不可以使用聚合函数 在查询条件中可以使用聚合函数
在数据分组前进行过滤 在数据分组后进行过滤
针对 数据库文件进行过滤(直接过滤表中字段) 针对查询结果进行过滤(根据前面已经查询出的字段)
不可以使用字段别名 可以使用字段别名

 

代码实操: 

# 统计每个部门年龄在30岁以上的员工的平均薪资并且保留平均薪资大于10000的部门
'''编写SQL语句 不要指望着一步到位 边写边看慢慢拼凑'''

# 1.先获取每个部门年龄在30岁以上的员工的平均薪资

  先筛选出30岁以上的员工数据 然后再对数据进行分组

  select post , avg(salary) from emp where age>30 group by post;

# 2.再过滤出平均薪资大于10000的数据

需要针对分组之后的数据再次筛选 需要使用having而不是where

select post avg(salary) from emp

where age > 30

group by post 

having avg(salary) > 10000

;

改进篇

针对聚合函数 如果还需要在其他地方作为条件使用 可以先起别名

select post avg(salary) as avg_salary from emp 

where age>30

group by post 

having avg_salary > 10000

;

 

查询关键字之distinct去重

distinct关键字的主要作用就是对数据库表中一个或者多个字段重复的数据进行过滤,只返回其中的一条数据给用户。

  select distinct age from emp;

去重的前提:

  数据不可以包含主键 

  对字段进行去重,要保证distinct在所有字段的最前面

注意事项:

  等我们学到django orm之后 数据会被封装成对象 
  那个时候主键很容易被我们忽略 从而导致去重没有效果!!!  

 

查询关键字之order by排序

oeder by    排序

asc  升序关键字(从小到大) 可以省略

desc 降序关键字 (从大到小)

 

代码实操

# 1.按照薪资高低排序

select * from emp order by salary;   # 默认是升序

select * from emp order by salary asc;

select * from emp order by salary desc;  # 降序

# 2.先按照年龄升序排序  如果年龄相同  则再按照薪资降序排序

select * from emp order by age,salary desc;

# 3.统计各部门年龄在10岁以上的员工平均工资  并且保留平均工资大于1000的部门并按照降序进行排序

select post,avg(salary) as avg_salary from emp

where age > 10

group by post

having avg_salary > 1000

oerder by avg_salary desc;

 

查询关键字之limit分页 

  limit关键字主要用于指定查询结果从哪条记录开始显示,一共显示多少条记录

 

用法:

limit 记录数 记录数表示需要显示的数据条数  如果“记录数”的值小于查询结果的总数,则会从第一条记录开始,显示指定条数的记录。如果“记录数”的值大于查询结果的总数,则会直接显示查询出来的所有记录。

limit  初始位置,记录数  一般第一个参数(初始位置)从0开始 两个参数必须是正整数

代码实操:

# 1.限制只展示五条数据

select * from emp limit 5;  

# 2.显示第五条数据后每页显示五条数据

select * from emp limit 5,5;

# 3.查询工资最高的人的详细信息

先对表中所有工资进行降序 再只展示一条数据

select *from emp order by salary desc limit 1;

 

查询关键字之regexp正则

^ 表示字符串的开头
$ 表示字符串的结尾

. 表示任意单个字符

.*表示任意长度的的任意字符

| 表示''或者''的意思

# 1. 查找表中首字母 j 开头的 n或者y结尾的 中间字符不限的全部姓名

select * from emp where name regexp'^j.*(n|y)$';

 

多表查询思路

多表查询的思路总共就两种

1. 子查询

就相当于我们日常生活中解决问题的方式(一步步解决)

将一条SQL语句的查询结果加括号当作另外一条SQL语句的查询条件

eg:

  以昨天的员工表和部门表为例  查询Jason所在的部门名称

    子查询的步骤:

      1. 先查Jason所在的部门编号

      2.根据部门编号去部门表种查找部门名称

 

2. 连表操作

  现将多张表拼接到一起  形成一张信息更全面的大表 然后再使用单表查询获取数据

eg:

  以昨天的员工表和部门表为例 查询Jason所在的部门名称

    连表操作:

      1. 先将员工包和部门表按照某个字段拼接到一起

      2. 基于单表查询数据

 

代码实操:

create table dep(
		id int primary key auto_increment,
    name varchar(32)
  );

create table emp(
  id int primary key auto_increment,
   name varchar(32),
   gender enum('male','female','others') default 'male',
   age int,
   dep_id int
 );

insert into dep values(200,'技术'),(201,'人力资源'),(202,'销售'),(203,'运营'),(205,'安保');
insert into emp(name,age,dep_id) values('jason',18,200),('tony',28,201),('oscar',38,201),('jerry',29,202),('kevin',39,203),('jack',48,204);

# 使用子查询 获取jason所在的部门名称 

# 1.先获取jason的部门编号

select dep_id from emp where name='jason';

# 2.将结果加括号作为查询条件 通过jason部门编号获取到部门名称

select name from dep where id=(select dep_id from emp where name='jason'); 

 

# 使用连表操作  获取jason所在的部门名称

使用笛卡尔积

select * from emp,dep;  # 会将所有的数据全部对应一遍

select * from emp,dep where emp.dep_id=dep.id; # 将emp表中dep_id和dep表中id两者对应的数据显示出来  效率较低

  1. 一条sql语句的查询结果,可以看作是一张虚拟表

  2. 如果一条sql语句中涉及到多张表的字段名称编写 建议使用表名作为前缀便于区分 比如多个表内都包含id字段 如果不加前缀 就会报错

 

连表操作关键字

inner join  内连接

select * from emp inner join dep on emp.dep_id=dep.id;

只链接两张表内共有的数据

 

left join  左链接

select * from emp left join dep on emp.dep_id=dep.id;

以左表为基准  展示所有的数据  没有对应的数据则用NULL填充

 

right join  右链接 

select * from emp right join dep on emp.dep_id=dep.id;

以右表为基准 展示所有的数据 没有对应的数据则用NULL填充

 

union  全链接

select * from emp union dep on emp.dep_id=dep.id;

左右两表数据全部展示  没有对应项则用NULL填充

 

答案

  select dep.name from emp inner join dep on ep.dep_id=dep.id

  where emp.name='jason';

 

学了连表操作 免不了优化一下

思路:之前我们把一个取值操作起别名,这两表拼接不得把拼接后的结果起个别名当作一张表来使用?又能去和另一张表去做两两拼接啦

select * from emp inner join (select emp.id as epd,emp.name,dep.id from emp inner join dep on emp.dep_id=dep.id) as t1

on emp.id=t1.epd;

 

可视化软件之Navicat

Navicat可以充当很多数据库软件的客户端 提供了图形化界面能够让我们更加快速的操作数据库
# 下载
	navicat有很多版本 并且默认都是收费使用
  正版可以免费体验14天 
  针对这种图形化软件 版本越新越好(不同版本图标颜色不一样 但是主题功能是一样的)
# 使用
	内部封装了SQL语句 用户只需要鼠标点点点就可以快速操作
  连接数据库  创建库和表 录入数据 操作数据
  外键 SQL文件 逆向数据库到模型 查询(自己写SQL语句)
  # 使用navicat编写SQL 如果自动补全语句 那么关键字都会变大写
  SQL语句注释语法(快捷键与pycharm中的一致 ctrl+?)
  	# 
    --
# 运行SQL文件

 

多表查询练习题

1、查询所有的课程的名称以及对应的任课老师姓名
4、查询平均成绩大于八十分的同学的姓名和平均成绩
7、查询没有报李平老师课的学生姓名
8、查询没有同时选修物理课程和体育课程的学生姓名
9、查询挂科超过两门(包括两门)的学生姓名和班级

-- 1、查询所有的课程的名称以及对应的任课老师姓名
# 1.先明确需要几张表 course表 teacher表
# 2.大致查找一些表中的数据情况
# 3.既然是多表查询 那么查询思路 子查询 连表操作(复杂的SQL需要两者配合使用)
# 4.编写完成后 使用美化功能 将SQL语句规范化
-- SELECT
-- 	course.cname,
-- 	teacher.tname 
-- FROM
-- 	course
-- 	INNER JOIN teacher ON course.teacher_id = teacher.tid;
-- 4、查询平均成绩大于八十分的同学的姓名和平均成绩
# 1.先明确需要用到几张表 student score
# 2.大致查看一下两张表里面的数据
# 3.先获取平均成绩大于80分的学生信息(按照student_id分组)
-- select score.student_id,avg(num) as avg_num from score group by score.student_id having avg_num>80;
# 4.结果需要从两个表里面的获取  student  SQL语句执行之后的虚拟表
-- SELECT
-- 	student.sname,
-- 	t1.avg_num 
-- FROM
-- 	student
-- 	INNER JOIN ( SELECT student_id, avg( num ) AS avg_num FROM score GROUP BY score.student_id HAVING avg_num > 80 ) AS t1 ON student.sid = t1.student_id;
-- 7、查询没有报李平老师课的学生姓名
# 此题有两种思路 第一种是正向查询 第二种是反向查询(先查所有报了李平老师课程的学生id 之后取反即可)
# 1.先明确需要用到几张表  四张表
# 2.先查询李平老师的编号
-- select tid from teacher where tname='李平老师'
# 3.再查李平老师教授的课程编号
-- select cid from course where teacher_id=(select tid from teacher where tname='李平老师')
# 4.根据课程编号 去score表中筛选出所有选了课程的学生编号
-- select distinct student_id from score where course_id in (select cid from course where teacher_id=(select tid from teacher where tname='李平老师'));
# 5.根据学生编号去学生表中反向筛选出没有报李平老师课程的学生姓名
-- SELECT
-- 	sname 
-- FROM
-- 	student 
-- WHERE
-- 	sid NOT IN ( SELECT DISTINCT student_id FROM score WHERE course_id IN ( SELECT cid FROM course WHERE teacher_id = ( SELECT tid FROM teacher WHERE tname = '李平老师' ) ) )
-- 8、查询没有同时选修物理课程和体育课程的学生姓名(两门都选了和一门都没选的 都不要 只要选了一门)
# 1.先明确需要用到几张表 三张
# 2.先获取物理课程和体育课程的编号
-- select cid from course where cname in ('物理','体育');
# 3.再去分数表中筛选出选了物理和体育的数据(包含了选了一门和两门 没有选的就已经被排除了)
-- select * from score where course_id in (select cid from course where cname in ('物理','体育'))
# 4.如何剔除选了两门的数据(按照学生id分组 然后对课程计数即可)
-- select student_id from score where course_id in (select cid from course where cname in ('物理','体育'))
-- group by student_id HAVING count(course_id) = 1;
# 5.根据上述学生id号筛选出学生姓名
-- SELECT
-- 	sname 
-- FROM
-- 	student 
-- WHERE
-- 	sid IN (
-- 	SELECT
-- 		student_id 
-- 	FROM
-- 		score 
-- 	WHERE
-- 		course_id IN ( SELECT cid FROM course WHERE cname IN ( '物理', '体育' ) ) 
-- 	GROUP BY
-- 		student_id 
-- 	HAVING
-- 	count( course_id ) = 1 
-- 	)
-- 9、查询挂科超过两门(包括两门)的学生姓名和班级
# 1.先明确需要几张表  三张表
# 2.先去score表中筛选出所有不及格的数据
-- select * from score where num < 60;
# 3.如何筛选每个学生挂科的门数(按照学生id分组 对学科计数即可)
-- select student_id from score where num < 60 group by student_id 
-- HAVING count(course_id) >= 2;
# 4.由于最终的结果需要取自两张表 所以应该拼接
-- select student.sname,class.caption from class inner join student on class.cid=student.class_id;
# 5.使用步骤3获取到的学生编号 对步骤4的表结果筛选数据
SELECT
	student.sname,
	class.caption 
FROM
	class
	INNER JOIN student ON class.cid = student.class_id 
WHERE
	student.sid IN ( SELECT student_id FROM score WHERE num < 60 GROUP BY student_id HAVING count( course_id ) >= 2 );
  
  
"""
重点掌握上述五道题目即可 如果还想扩展 可以考虑下面的题目
https://www.cnblogs.com/Dominic-Ji/p/10875493.html

 

  

 

posted @ 2022-05-09 00:06  ji哩咕噜  阅读(132)  评论(0编辑  收藏  举报