第六章 使用数字
1 常用聚集函数(空值处理)
2 生成累计和
--公司为了查看用人成本,需要对员工的工资进行累加,
--以便查看员工人数与工资支出之间的对应关系。
SELECT Empno,
Ename,
Sal,
SUM(Sal) Over(ORDER BY Empno) AS 成本累加,
(SELECT Listagg(Sal, '+') Within GROUP(ORDER BY Empno)
FROM Emp b
WHERE b.Empno <= a.Empno
AND Deptno = 30) 计算公式
FROM Emp a
WHERE Deptno = 30
ORDER BY Empno;
--分析函数、rows开窗、range开窗、标量方式的累加方法对比。
SELECT Empno,
Sal,
SUM(Sal) Over(ORDER BY Empno) AS 分析函数,
SUM(Sal) Over(ORDER BY Empno Rows BETWEEN Unbounded Preceding AND CURRENT ROW) AS Row开窗,
SUM(Sal) Over(ORDER BY Empno RANGE BETWEEN Unbounded Preceding AND CURRENT ROW) AS Range开窗,
(select sum(sal) from emp b where b.empno<=a.empno and deptno=30) as 标量
FROM Emp a
WHERE Deptno = 30
ORDER BY 1;
3 计算累计差
4 更改累计和的值
--银行存取款问题 PY取款,PR存款
create or replace View V(id,amt,trx)
as
select 1,500,'PR' from dual union all
select 2,200,'PY' from dual union all
select 3,300,'PR' from dual union all
select 4,200,'PY' from dual union all
select 5,400,'PR' from dual union all
select 6,100,'PY' from dual ;
SELECT * FROM v ;
SELECT Id,
CASE WHEN Trx = 'PY' THEN '取款' ELSE '存款' END 存取类型,
Amt 金额,
SUM(case when Trx = 'PY' THEN -amt ELSE amt END) over(order by id) as 余额
FROM v
ORDER BY Id;
5 返回部门工作排名前三位的员工
--PARTITION BY 子句可以把主查询返回的数据分组进行分析。
--row_number,rank,dense_rank来分组partition by生成序号。
SELECT Deptno,
Empno,
Sal,
Row_Number() Over(PARTITION BY Deptno ORDER BY Sal DESC) AS Row_Number,
Rank() Over(PARTITION BY Deptno ORDER BY Sal DESC) AS Rank,
Dense_Rank() Over(PARTITION BY Deptno ORDER BY Sal DESC) AS Dense_Rank
FROM Emp
--查询各部门工资前三名
SELECT *
FROM (SELECT Deptno,
Empno,
Sal,
Row_Number() Over(PARTITION BY Deptno ORDER BY Sal DESC) AS Row_Number
FROM Emp)
WHERE Row_Number <= 3
6 计算出现次数最多的值
--查看部门中那个工紫等级的员工最多。
--1.计算不同工资出现的次数
--2.按次数排序生成序号
--3.根据序号过滤等到需要的结果
--4.利用partition by 子句分别查询各部门那个工作等级的员工最多
SELECT Deptno, Sal,次数排序
FROM (SELECT Deptno,
Sal,
Dense_Rank() Over(PARTITION BY Deptno ORDER BY 出现次数 DESC) AS 次数排序
FROM (SELECT Sal, Deptno, COUNT(*) AS 出现次数
FROM Emp
GROUP BY Deptno, Sal) x) y
WHERE 次数排序 = 1;
7 返回最值所在行数据
--标量
SELECT Deptno,
Empno,
(SELECT MAX(b.Ename) FROM Emp b WHERE b.Sal = a.Max_Sal) as 工资最高的人,
(SELECT MAX(b.Ename) FROM Emp b WHERE b.Sal = a.Min_Sal) as 工资最低的人,
Ename,
Sal
FROM (SELECT Deptno,
Empno,
MAX(Sal) Over(PARTITION BY Deptno) AS Max_Sal,
MIN(Sal) Over(PARTITION BY Deptno) AS Min_Sal,
Ename,
Sal
FROM Emp
WHERE Deptno = 10) a
--分析函数
select deptno,
empno,
max(ename) keep(dense_rank first order by sal) over(partition by deptno) as 工资最低的人,
max(ename) keep(dense_rank last order by sal) over(partition by deptno) as 工资最高的人,
ename,
sal
from emp
where deptno=10
order by 1,6 desc;
--first、last语句也可以放在group里与其他聚合函数一样使用
--但要去掉后面的over(partition by xxx)
select deptno,
min(sal),
max(ename) keep(dense_rank first order by sal) as 工资最低的人,
max(sal) as max_sal,
max(ename) keep(dense_rank last order by sal) as 工资最高的人
from emp
group by deptno
--当有相同数据时,min和max的区别
SELECT Deptno,
Empno,
Ename,
Sal,
To_Char(Wmsys.Wm_Concat(Ename) Keep(Dense_Rank LAST ORDER BY Sal)
Over(PARTITION BY Deptno)) AS 工资最高的人群,
MAX(Ename) Keep(Dense_Rank LAST ORDER BY Sal) Over(PARTITION BY Deptno) AS 工资最高的人max,
MIN(Ename) Keep(Dense_Rank LAST ORDER BY Sal) Over(PARTITION BY Deptno) AS 工资最高的人min
FROM Emp
WHERE Deptno = 10
ORDER BY 1, 4 DESC;
8 fisrt_value
看上去这个语句没有问题,但是若把desc和first_value修改为asc和last_value来看一下;
SELECT Deptno,
Empno,
first_Value(Ename) Over(PARTITION BY Deptno ORDER BY Sal desc,ename) AS 工资最高的人之一,
first_Value(Ename) Over(PARTITION BY Deptno ORDER BY Sal desc,ename desc) AS 工资最高的人之一,
Ename,
Sal
FROM Emp
WHERE Deptno = 10
ORDER BY 1, 6 DESC;
9 求总和的百分比
--1.分组汇总
--2.通过分析函数取总合计
--3.得到总合计后就可以计算比例
SELECT y.*,round((工资合计/总合计)*100,2) as 工资比例
FROM (SELECT Deptno, 工资合计, SUM(工资合计) over() AS 总合计
FROM (SELECT Deptno, SUM(Sal) 工资合计
FROM Emp
WHERE Deptno IS NOT NULL
GROUP BY Deptno) x) y
ORDER BY 1;
SELECT Deptno, Round(Ratio_To_Report(工资合计) Over() * 100, 2) AS 工资比例
FROM (SELECT Deptno, SUM(Sal) 工资合计
FROM Emp
WHERE Deptno IS NOT NULL
GROUP BY Deptno)
ORDER BY 1;
SELECT Deptno,
Empno,
Ename,
Sal,
Round(Ratio_To_Report(Sal) Over(PARTITION BY Deptno) * 100, 2) as 工资占比
FROM Emp
ORDER BY 1, 2;