MySQL攻略 - 单表查询增强、多表查询、子查询

MySQL单表表查询 - 增强

在前面我们讲过mysql表的基本查询,但是都是对一张表进行的查询,这在实际的软件开发中,还远远的不够。
下面我们讲解的过程中,将使用前面创建三张表

(emp,dept,salgrade)

部门表源码(文件源码)

CREATE TABLE dept (/*部门表*/
deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
dname VARCHAR(20) NOT NULL DEFAULT "",
loc VARCHAR(13) NOT NULL DEFAULT ""
);
INSERT INTO dept VALUES (10,'ACOUNTING ','NEW YORK'),
												(20,'RESEARCh' , 'DALAS '),
												(30,'SALRS', 'CHICGO '),
												(40,'OPERATION', 'BoTo ');
	#创建表EMP雇员
	CREATE TABLE emp(empno MEDIUMINT UNSIGNED NOT NULL,/*编号*/
									ename VARCHAR(20) NOT NULL DEFAULT '' ,/*名字*/
									job VARCHAR(9) NOT NULL DEFAULT '' ,/*工作*/
									mgr MEDIUMINT UNSIGNED ,/*上级编号*/
									hiredate DATE NOT NULL,/*入职时间*/
									sal DECIMAL(7,2)NOT NULL,/*薪水*/
									comm DECIMAL(7,2),/*红利*/
									deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0/*部门编号*/) ;
	
	INSERT INTO emp VALUES(7369,'SMITH ','CLERK', 7902,'1990-12-17',800.00, NULL , 20),
												(7499,'ALLEN','SALESMAN ', 7698,'1991-2-20',1600.00,300.00,30),
												(7521,'WARD','SALESMAN' ,7698,'1991-2-22',1250.00,500.00,30),
												(7566,'TONES','AANACEN', 7098,'1991-2-22 ',1250.00,500.00,30),
												(7654,'MARTIN ','SALESMAN ', 7698,'1991-9-28', 1250.00,1400.00,30),
												(7698,'BLAKE','MANAGER', 7839,'1991-5-1', 2850.00,NULL,30 ),
												(7900,'JAMES', 'CLERK', 7698,'1991-12-3 ',950.00,NULL,30),
												(7902,'FORD ','ANALYST', 7566,'1991-12-3', 3000.00,NULL, 20 ),
												(7934,'MILLER', 'CLERK ', 7782,'1992-1-23',1300.00,NULL,10);
-- 	工资级别表
CREATE TABLE salgrade
(
grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,	/*工资级别*/
losal DECIMAL(17,2) NOT NULL,		/*该级别最低工资*/
hisal DECIMAL(17,2) NOT NULL		/*该级别最高工资*/
);
INSERT INTO salgrade VALUES (1,700,1200);
INSERT INTO salgrade VALUES (2,1201,1400);
INSERT INTO salgrade VALUES (3,1401,2000);
INSERT INTO salgrade VALUES (4,2001,3000);
INSERT INTO salgrade VALUES (5,3001,9999);
												
delete  from emp 
delete from dept
delete from salgrade
select * from emp

like(案例)

-- 使用where子句
-- 			如何查找1992.1.1后入职的员工
-- 			(在mysql中,日期类型可以直接比较)
-- 			(需要注意日期格式)
select * from emp where hiredate >= '1992-01-01';

-- 如何使用like操作符
-- 			%:表示0到多个任意字符      _︰表示单个字符
-- 			?如何显示首字符为S的员工姓名和工资
select ename,sal from emp where ename like 'S%' 

-- 			如何显示姓名第三个字符为大写R的所有员工的姓名和工资
select ename,sal from emp where ename like '__R%'

-- 			如何显示没有上级的雇员的情况
select * from emp where mgr is null;

-- 查询表结构
desc emp


select * from emp

order by(案例)

-- 如何按照工资的从低到高的顺序,显示雇员的信息
select * from emp order by sal 

-- 按照部门号升序,而雇员的工资降序排列,显示雇员信息
select * from emp order by deptno ASC,sal DESC 

分页查询(案例)

-- 按雇员的id号升序取出,每页显示3条记录,请分别显示第一页,第二页,第三页
-- 基本语法:select ... limit start, rows表示从start+1行开始取,取出rows行, start 从0开始计算

-- 第一页
select * from emp order by empno 
									limit 0,3 
-- 第二页
select * from emp order by empno
									limit 3,3
									
-- 第三页
select * from emp order by empno
									limit 6,3

-- 推导一个公式
select * from emp order by empno
									limit 每页显示记录数 * (第几页 - 1),每页显示的记录数
								

group by(案例)

-- 使用分组函数和分组子句group by
-- 显示每种岗位的雇员总数
select count(*) ,job from emp group by job 
-- 显示每种岗位的雇员总数、平均工资。
select count(*),job,avg(sal) from emp group by job 

-- 显示雇员总数,以及获得补助的雇员数。
select count(*),count(comm) from emp		-- 注意这里count(comm)如果不为空则统计
-- 显示雇员总数,以及获得没有获得补助的雇员数
select count(*),count(if(comm is null,1,null)) from emp 
select count(*),count(*) - count(comm) from emp

-- 显示管理者的总人数。(去重)
select count(distinct mgr) from emp 

-- 显示雇员工资的最大差额。
select MAX(sal) - MIN(sal) from emp


select * from emp

综合使用

如果select语句同时包含有group by ,having , limit,order by那么他们的顺序是group by , having , order by,limit)

请添加图片描述

案例

-- 请统计各个部门的平均工资,并县是大于1000的,并且按照平均工资从高到纸排序,取出前两行记录.
select deptno,avg(sal) as avg_sal from emp
													group by deptno 
													having avg_sal > 1000
													order by avg(sal)
													DESC limit 0,2

MySQL多表查询(重点,难点)

请添加图片描述

概念

多表查询是指基于两个以上的表查询,在实际应用中,查询单个表可能不能满足你的需求,(如下面的课堂练习),需要使用到(dept表和emp表)

多表查询练习

-- 多表查询
-- ?显示雇员名,雇员工资及所在部门的名字【笛卡尔集】
/*
			分析:
			1.雇员名,雇员工资 来自 emp表
			2.部门的名字 来自dept表
			3.需求对emp 和 dept查询
*/
-- 在默认情况下:当两个表查询时,规则
-- 1.从第一张表中,取出一行 和第二张表的每一行进行组合,返回结果[含有两张表的所有列]
-- 2.一共返回的记录数,第一张表行数 * 第二张表的行数 
-- 3. 这样多表查询默认返回处理结果,称为【笛卡尔集】
-- 4.解决这个多表的关键就是要写出正确的过滤条件 where
-- 5.当我们需要指定显示某个表的列是,需要   表.列表

select * 
				from emp,dept

select ename,sal,dname
				from emp,dept
				where emp.deptno = dept.deptno
				
select ename,sal,dname,emp.deptno
				from emp,dept
				where emp.deptno = dept.deptno

select * from emp
select * from dept

注意

多表查询的条件不能少于表的个数 -1,否则会出现笛卡尔集

(比如两个表,过滤条件必须有一个)

多表查询练习2

请添加图片描述

-- ?如何显示部门号为10的部门名、员工名和工资
select dname,ename,sal,emp.deptno from emp,dept where  emp.deptno = 10 and emp.deptno = dept.deptno;

-- ?显示各个员工的姓名,工资,及其工资的级别
select grade,ename,sal from emp,salgrade -- [笛卡尔集]
select grade,ename,sal from emp,salgrade where sal between losal and hisal 
										order by sal


desc salgrade
desc emp

自连接

概念

自连接是指在同一张表的连接查询【同一张表看做两张表】

案例题目

思考题:显示公司员工名字和他的上级的名字

请添加图片描述

自连接特点

  1. 把同一张表当做两张表使用
  2. 需要给表取别名 | 表明 表别名
  3. 列名不明确,可以指定列的别名 列名 as 列的别名

MySQL表子查询

什么是子查询

子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询

单行子查询

单行子查询是指只返回一行数据的子查询语句

案例练习

-- 子查询演示
-- 请思考:如何显示与smith同一部门的所有员工?
/*
		1.先查询到 smith的部门号
		select deptno from emp where ename = 'smith'
		2.把这条语句当做子查询来使用
		3.条件:emp.deptno = smith.deptno
*/

select *
				from emp
				where emp.deptno = (
									select deptno 
									from emp
									where ename = 'smith'
									)  

多行子查询

多行子查询指返回多行数据的子查询,使用关键字in

-- 查询部门30的工作相同的雇员的名字、岗位、工资、部门号,
-- 但是不含30号部门自己的雇员

/*
		1.查询到30号部门有哪些工作
			select distinct job from emp where deptno = 30
		2.把上面查询的结果当做子查询使用
*/
select distinct job 
							from emp
							where deptno = 30		
select ename,job,sal,deptno 
				from emp 
				where job in(
										select distinct job 
										from emp
										where deptno = 30
				) and deptno != 30	
select * from emp
select * from dept

all、any(操作符)

-- 如何显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
-- select sal from emp where deptno = 30

-- all
select ename,sal,deptno 
								from emp 
								where sal > all(
									select sal from emp where deptno = 30
								)
								
-- max
select ename,sal,deptno 
								from emp 
								where sal > (
									select max(sal) from emp where deptno = 30
								)
								
-- 如何显示工资比部门30的'其中一个'员工的工资高的员工的姓名、工资和部门号
-- any
select ename,sal,deptno
								from emp
								where sal > any(
									select sal from emp where deptno = 30
								)
								
-- min
select ename,sal,deptno
								from emp
								where sal >(
									select min(sal) from emp where deptno = 30
								)

子查询临时表

子查询当做临时表使用

案例练习1

没有表,看一下就行了

-- 查询ecshop中各个类别中,价格最高的商品
-- 
-- 查询商品表
-- 先得到 各个类别中,价格最高的商品 max + group by cat_i,当做临时表
-- 把子查询当做一个临时表可以解决很多很多复杂的查询

select cat_id,max(shop_price)
										from ecs_goods
										group by cat_id
										
select good_id,ecs_goods.cat_id,goods_name,shop_price
										from (
											select cat_id,max(shop_price) as max_price
											from ecs_goods
											group by cat_id
										)temp,ecs_goods
										where temp.cat_id = ecs_goods.cat_id
										and temp.max_price = ecs_goods.shop_price

案例练习2

-- 问题:查找每个部门工资高于本部门平均工资的人的资料
-- 这里要用到数据查询的小技巧,把一个子查询当作一个临时表使用 

-- 1.得到本部门的平均工资
select deptno,avg(sal) as '平均工资'
			from emp
			group by deptno
			
-- 2.把上面的结果当作子查询,和 emp进行多表查询
select ename,emp.sal,emp.deptno,temp.avg_sal
			from emp,(
						select deptno,avg(sal) as avg_sal
						from emp
						group by deptno
				) temp
			where emp.sal > temp.avg_sal and emp.deptno = temp.deptno

案例练习3

-- 问题:得到每个部门工资最高的人的详细资料
-- 1.得到本部门的最高工资
select deptno ,max(sal)
			from emp
			group by deptno
			
-- 2.把上面的结果当作子查询,和emp进行多表查询
select *
			from emp,(
					select deptno ,max(sal) as max_sal
					from emp
					group by deptno
			)temp
			where temp.max_sal = emp.sal and temp.deptno = emp.deptno
			

案例练习4

-- 显示每个部门的信息(包括:部门名,编号,地址)和人员数量
-- 1.各个部门的人员数量,构建一个临时表
select count(*),deptno
			from emp
			group by deptno;
-- 2.通过临时表建立查询
select dname,dept.deptno,dept.loc,temp.per_num as '人数'
			from dept,(
						select count(*)as per_num,deptno
						from emp
						group by deptno
					) temp
					where temp.deptno = dept.deptno
					
					
					
-- 第二种写法 表.* 表示将该表所有的列都显示出来,可以简化sql语句
-- 在多表查询中,当多个表的列不重复时,才可以直接写列名
select temp.*,dname,loc
			from dept,(
						select count(*)as per_num,deptno
						from emp
						group by deptno
					) temp
					where temp.deptno = dept.deptno
					

注意

  • 子查询别名使用

多列子查询

多列子查询则是指查询返回多个列数据的子查询语句

-- 如何查询与smith的部门和岗位完全相同的所有雇员(并且不包含smith本人)
-- 1.得到smith的部门和岗位
select deptno,job 
							from emp
							where ename = 'SMITH'
							
-- 2.把上面的查询当做子查询来使用,并且使用多列子查询的语法进行匹配

select *
			from emp
			where  (deptno, job) = (
								select deptno,job 
								from emp
								where ename = 'smith'
							) and ename != 'smith'

思考:查询表中与某位同学各科成绩相同的学生(不再示范)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鬼鬼骑士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值