Oracle 查询优化改写(第六章)

第六章 使用数字

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;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小猪宝宝哦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值