oracle数据库基础:DQL语言基础(下)

DQL语言基础(下)

5、分组查询

group by

语法:

select 分组函数,列(要求出现在group by的后面)
from 表名
group by 分组的列表
order by 子句

在使用分组函数的时候:
如果还使用了group by分组,那么就表示先分组,然后对每一个小组使用聚合函数。
如果没有使用group by分组,那么就表示全部数据是一个默认小组,然后对这个全部数据使用聚合函数。

例一:查询s_emp表中所有员工的平均工资(没有使用group by进行分组)

select avg(salary) from s_emp;

例二:查询s_emp表中不同部门的员工的平均工资

select dept_id,avg(salary) from s_emp group by dept_id order by dept_id;

例三:查询s_emp表中每个部门员工的最高工资

select dept_id,max(salary) from s_emp group by dept_id;

group by …having…

having用来添加筛选条件:
语法:

select 分组函数,列(要求出现在group by的后面)
from 表名
group by 分组的列表
having 筛选条件
order by 子句

例题:查询s_emp表中部门的平均工资大于等于1400的部门

select dept_id,avg(salary)
from s_emp
group by dept_id
having avg(salary)>=1400;

??思考??:where和having同样是用来筛选条件的,有什么区别
答:
(1)where和having都是做条件筛选的
(2)where执行的时间比having要早
(3)where后面不能出现组函数
(4)having后面可以出现组函数
(5)where语句要紧跟from后面
(6)having语句要紧跟group by后面

案例:
例一:查询s_emp表中,部门的平均工资大于等于1400的部门,并且显示出这些部门的名字,同时按照部门编号进行排序。
步骤:
(1)查询出基本需求

select  dept_id,avg(salary)
from  s_emp
group by  dept_id
having  avg(salary)>=1400
order by  dept_id;

(2)加入多表查询,并且分别给表起别名

select  se.dept_id,avg(se.salary)
from  s_emp se,s_dept sd
group by  se.dept_id
having  
avg(se.salary)>=1400
order by 
se.dept_id;

(3)查询出s_dept表中的部门名称,并且进行等值连接

select  se.dept_id,avg(se.salary),sd.name
from  s_emp se,s_dept sd
where  se.dept_id = sd.id
group by  se.dept_id
having  avg(se.salary)>=1400
order by  se.dept_id;

(4)select语句后出现了组函数,那么没有被组函数修饰的列,需要放到group by分组后面

select  se.dept_id,avg(se.salary),sd.name
from  s_emp se,s_dept sd
where  se.dept_id = sd.id
group by  se.dept_id,sd.name
having  avg(se.salary)>=1400
order by  se.dept_id;

例二:查询s_emp表每个部门的最大工资数,并且显示出这个最大工资的员工的名字,以及该部门的名字、该部门所属区域,并且使用部门编号进行排序
步骤:
(1)查询每个部门的最大工资,排序

select  max(salary),dept_id
from  s_emp
group by  dept_id
order by  dept_id;

(2)显示出这个最大工资的员工名字

select  max(s1.salary) ,s1.dept_id,s2.last_name
from  s_emp s1,s_emp s2
where  s2.dept_id=s1.dept_id 
group by  s1.dept_id,s2.last_name,s2.salary
having   max(s1.salary)=s2.salary
order by  s1.dept_id;

(3)显示出这个最大工资的员工名字,显示部门名称、部门所在地区

select  max(s1.salary) ,s1.dept_id,s2.last_name,d.name,r.name 
from  s_emp s1,s_emp s2,s_dept d, s_region r 
where  s2.dept_id=s1.dept_id  
and s1.dept_id=d.id 
and d.region_id=r.id 
group by  s1.dept_id,s2.last_name,s2.salary,d.name,r.name
having   max(s1.salary)=s2.salary
order by  s1.dept_id;

完整select语句执行顺序

现在一个select查询语句,由以下几部分组成:

select 字段1,字段2
from 表
where 条件
group by 分组条件
having 分组筛选条件
order by 排序条件

select语句执行顺序:

  1. from子句,组装来自表的数据,有可能是多张表
  2. where子句,基于指定的条件对记录行进行筛选
  3. group by子句,将数据划分为多个分组
  4. 使用聚合函数对没个小组中的数据进行计算
  5. having子句,进行条件筛选,这里可以使用聚合函数的计算结果
  6. 计算所有的运算表达式,主要是select部分7. order by子句,对结果集进行排序

聚合函数能够出现的位置

  1. select后面
  2. having后面
  3. order by后面

注意:
1、where后面一定【不能】出现组函数
2、如果select、having语句后面出现了组函数,那么select、having后面没有被组函数修饰的列,就必须出现在group by 后面 (非常重要)

group by和having的关系

  1. group by可以单独存在,后面可以不出现having语句
  2. having不能单独存在,如果需要出现,那么就必须出现在group by后面

6、连接查询(多表查询)

多表查询,又称表联合查询,即一条sql语句涉及到的表有多张,表中的数据通过特定的连接,进行联合显示。

分类

1、等值连接

利用一张表中某列的值,和另一张表中某列的值相等的关系,把俩张表连接起来,满足条件的数据才会组合。

例如:查询员工的名字、部门编号、部门名字

select last_name,dept_id,s_dept.id,name
from s_emp,s_dept
where s_emp.dept_id=s_dept.id;

为了好区分,可以为每张表起别名

select se.last_name,se.dept_id,sd.id,sd.name 
from s_emp se,s_dept sd
where se.dept_id=sd.id;

2、不等值连接

假设数据库中有一张工资等级表 salgrade
内容如下:
id salgrade losal hisal
1 初级程序员 2000 4000
2 中级程序员 4000 6000

其中
gradeName 列表示等级名称
losal 列表示这个级别的最低工资数
hisal 列表示这个级别的最高工资数

让你查询出员工的名字、职位、工资、工资等级名称

select e.last_name, e.title, e.salray, s.gradeName
from   s_emp e, salgrade s
where   e.salray between s.losal and s.hisal

3、外连接

先分别在俩s_emp和s_dept表中插入新的数据
如下:

insert into s_emp(id,last_name) values(26,'tom');
insert into s_dept(id,name) values(60,'st');
commit;

注意,新员工tom不在任何部门中,新增部门st下面没有任何员工

此时使用等值连接查询结果,如下:

col last_name for a15
col name for a15

select last_name,dept_id,name
from s_emp,s_dept
where s_emp.dept_id=s_dept.id;

在这里插入图片描述
新增加的员工tom和新增的部门st都没被查询出来,
原本应该查处27条数据呀,怎们会数据会少呢?
因为此时
新增的员工tom和部门表中的数据连接不上,
新增的部门st也和员工表中的数据连接不上,
那么这俩条数据都是在等值连接中查询不出来的。
由此需要使用外连接了

语法:

select 查询列表
from 表1 别名 【连接类型】
join 表2 别名
on 连接条件
【where 筛选条件】
【group by 分组条件】
【having 筛选条件】
【order by 排序列表】

outer可以省去不写

3.1 左外连接

语法:
select 查询列表
from 表1 别名 【left outer】
join 表2 别名
on 连接条件
【where 筛选条件】
【group by 分组条件】
【having 筛选条件】
【order by 排序列表】

例如:查询所有员工,以及对应的部门的名字,没有部门的员工也要显示出来

select last_name,dept_id,name 
from s_emp left outer join s_dept
on s_emp.dept_id=s_dept.id;

在这里插入图片描述
在oracle中,左外连接,还可以简写成:

select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id=s_dept.id(+);

如若想查出一个表中的数据,就在另一张表上添加‘+’,是不是好记了点

3.2 右外连接

语法:
select 查询列表
from 表1 别名 【right outer】
join 表2 别名
on 连接条件
【where 筛选条件】
【group by 分组条件】
【having 筛选条件】
【order by 排序列表】

右外连接和左外连接一样使用

select last_name,dept_id,name 
from s_emp right outer join s_dept
on s_emp.dept_id=s_dept.id;

在这里插入图片描述
在oracle中,左外连接,也可以简写成:

select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id(+)=s_dept.id;
3.3 全连接

语法:
select 查询列表
from 表1 别名 【full】
join 表2 别名
on 连接条件
【where 筛选条件】
【group by 分组条件】
【having 筛选条件】
【order by 排序列表】

例如,查询所有员工 以及对应的部门的名字,没有任何员工的部门也要显示出来,没有部门的员工也要显示出来

select last_name,dept_id,name 
from s_emp full outer join s_dept 
on s_emp.dept_id=s_dept.id;

结果是左右俩边的表中,新增的数据tom和st,原来等值连接不上,现在也全都被查询出来了。

4、自连接

自连接就是一张表,自己和自己连接后进行查询

例如,查询每个员工的名字以及员工对应的管理者的名字

select s1.last_name,s2.last_name manager_name
from s_emp s1,s_emp s2
where s1.manager_id = s2.id;

7、子查询

子查询,也称嵌套查询,即一个select语句中嵌套了另外的一个或者多个select语句

子查询的思路就是,把第一个sql语句的查询结果,在第二个sql语句中使用,这时候第一条sql语句的结果,在第二条sql中就可以充当一个where条件中的一个值,或者充当一张虚拟的表。

例如,查询工资比Smith工资高的员工信息
步骤:
(1)查询Smith的工资数

select salary
from s_emp
where last_name='Smith'; 

//运行结果:  
 SALARY
 ----------       
 940

(2)查询工资比940高的员工信息

select last_name,salary
from s_emp
where salary>940;

(3)把第二步中的数字940替换成第一步中的sql语句即可,可以使用小括号包裹子查询

select last_name,salary
from s_empwhere salary>( 
	select salary 
	from s_emp 
	where last_name='Smith'
);

8、分页查询

因为表中数据过多,我们并不能一次全都查询出来交给前端去展示,而是需要每次按照提前设置好的要求,查询一部分数据给用户,当用户点击下一页的时候,再查出下一部分数据给用户。
实现分页的方式有很多,并且不同数据库,实现分页查询的方式也会不同,那么在Oracle中,可以使用伪列 rownum,再结合子查询来进行简单的实现。

8.1 伪列rownum

Oracle中,有一个特殊的关键字rownum,被称为:伪列
rownum只有Oracle数据中才有
rownum(伪列),就像表中的列一样,但是在表中并不存在
伪列只能用于查询,不能像其他列一样随便操作。
rownum表示为一个查询的结果的行号,从1开始,连续不断。
例如:

select rownum,last_name
from s_emp;

结果:
在这里插入图片描述

伪列,可以根据查询结果的条数自动生成并且一定是从1开始连续不断的数字伪列
rownum的本质就是给查询的一行行结果标上行号

当伪列用在where条件中时,只能有以下操作:
rownum=1;表示查询第一行的内容

select last_name
from s_emp
where rownum=1

rownum>0;表示查询所有行的内容

select last_name
from s_emp
where rownum>0

rownum<任意数n;表示查询小于前n行的内容

select last_name
from s_emp
where rownum<7

注意:rownum要么等于1,要么大于0,要么小于某个数

8.2 分页查询的使用

例一:例如,查询s_emp表中,前10条数据

select rownum rn,id,last_name,dept_id 
from s_emp 
where rownum<=10

例二:查询s_emp表中,第3~7条数据

select t.id,t.last_name,t.dept_id
from ( 	
	select rownum rn,id,last_name,dept_id  
	from s_emp 
	where rownum<=7) t
where t.rn>=3;

这sql中,给rownum起一个别名rn,然后把这个sql语句作为第二条sql语句的子查询,并且把它当做一张虚拟的表,那么这时候,这个虚拟表中的rn是可以当做普通的字段进行操作了

也可以通过操作结果集的方式求:

where last_name,id
from s_emp
where rownum<=10
minus
where last_name,id
from s_emp
where rownum<=6

9、操作结果集

union:取两个结果集的并集
union all:把两个结果集合在一起显示出来
minus:第一个结果集除去与第二个结果集中相同的部分
intersect:求两个结果集的交集

前提条件是,俩个结果集中查询的列要完全一致(名称和类型)

例如,取俩个结果集的并集

select last_name,dept_id,name 
from s_emp,s_deptwhere s_emp.dept_id=s_dept.id(+)
union
select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id(+)=s_dept.id;

例如,把俩个结果集合在一起显示出来

select last_name,dept_id,name 
from s_emp,s_deptwhere s_emp.dept_id=s_dept.id(+)
union all
select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id(+)=s_dept.id;

例如,第一个结果集除去第二个结果集和它相同的部分

select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id=s_dept.id(+)
minus
select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id(+)=s_dept.id;

例如,求俩个结果集的交集

select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id=s_dept.id(+)
intersect
select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id(+)=s_dept.id;

10、千年虫

在早期的计算机的程序中,规定了的年份仅用两位数来表示。假如是1971年,在计算机里就会被表示为71。但是到了2000年的时候这个情况就出现了问题,计算机读取出之前存的一个日期88,结果就是2088年。这样的话,计算机内部对年份的计算就会出现问题,这个事情当时被称为千年虫。

为了处理这个问题,后面就有了一种新的日期格式:rr
如果在存储日期数据的时候,年份采用的格式为rr,并且只提供了最后2位年份,那么年份中的前两位数字就由两部分共同确定,其规则如下:

规则1 :
如果指定年在00~ 49之间,并且当前年份在00~ 49之间,那么指定年的世纪就与当前年份的世纪相同。因此,指定年的前两位数字就等于当前年份的前两位数字。例如,如果指定年为15,而当前年份为2007,那么指定年就是2015

规则2:
如果指定年在50~ 99之间,并且当前年份在00~ 49之间,那么指定年的世纪就等于当前年份的世纪减去1。因此,指定年的前两位数字等于当前年份的前两位数字减去1。例如,如果指定年为75,而当前年份为2007,那么指定年就是1975

规则3:
如果指定年在00~ 49之间,并且当前年份在50~99之间,那么指定年的世纪就等于当前年份的世纪加上1。因此,指定年的前两位数字等于当前年份的前两位数字加上1。例如,如果指定年为15,而当前年份为2075,那么指定年就是2115

规则4:
如果指定年在5099之间,并且当前年份在5099之间,那么指定年的世纪就与当前年份的世纪相同。因此,指定年的前两位数字就等于当前年份的前两位数字。例如,如果指定年为55,而当前年份为2075,那么指定年就是2055

在这里插入图片描述

注意:rr格式并没有完全的解决俩位数年份保存的问题

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值