【SQL开发实战技巧】系列(十四):计算消费后的余额&计算银行流水累计和&计算各部门工资排名前三位的员工

简介: 本篇文章讲解的主要内容是:***通过模拟计算消费流水账及计算银行流水累计和讲解sum()over()函数使用场景、通过计算各部门工资排名前三位的员工小案例来介绍ROW_NUMBER、RANK、DENSE_RANK使用方法及区别***

前言

本篇文章讲解的主要内容是:通过模拟计算消费流水账及计算银行流水累计和讲解sum()over()函数使用场景、通过计算各部门工资排名前三位的员工小案例来介绍ROW_NUMBER、RANK、DENSE_RANK使用方法及区别
【SQL开发实战技巧】这一系列博主当作复习旧知识来进行写作,毕竟SQL开发在数据分析场景非常重要且基础,面试也会经常问SQL开发和调优经验,相信当我写完这一系列文章,也能再有所收获,未来面对SQL面试也能游刃有余~。


一、模拟计算消费流水账

首先生成样例数据:

SQL> with t as (
  2  select 1000 as 编号,'余额' as 项目,30000 as 金额 from dual
  3  union all
  4  select empno,to_char(rownum),sal from emp where deptno=10
  5  )
  6  select * from t;

        编号 项目                                             金额
---------- ---------------------------------------- ----------
      1000 余额                                          30000
      7782 1                                              2450
      7839 2                                              5000
      7934 3                                              1300

这是模拟的一个消费流水账,账户余额初始是30000,后面是三次消费的数据,现在有个需求:得到每笔费用消费后的余额。
如何做这个需求呢?
这里给出解决方案,如下:

SQL> with t as (
  2  select 1000 as 编号,'余额' as 项目,30000 as 金额 from dual
  3  union all
  4  select empno,to_char(rownum),sal from emp where deptno=10
  5  )
  6  select t.*,sum(case when 项目='余额' then 金额 else -金额 end )over(order by 编号) as 余额
  7  from t;

        编号 项目                                             金额         余额
---------- ---------------------------------------- ---------- ----------
      1000 余额                                          30000      30000
      7782 1                                              2450      27550
      7839 2                                              5000      22550
      7934 3                                              1300      21250

SQL> 

二、计算银行流水累计和

有如下临时表:

SQL> with t as
  2   (select 1 as id, 100 as amt, 'PR' as trx
  3      from dual
  4    union all
  5    select 2 as id, 100 as amt, 'PR' as trx
  6      from dual
  7    union all
  8    select 3 as id, 50 as amt, 'PY' as trx
  9      from dual
 10    union all
 11    select 4 as id, 100 as amt, 'PR' as trx
 12      from dual
 13    union all
 14    select 5 as id, 200 as amt, 'PY' as trx
 15      from dual
 16    union all
 17    select 6 as id, 50 as amt, 'PY' as trx
 18      from dual)
 19  select * from t;

        ID        AMT TRX
---------- ---------- ---
         1        100 PR
         2        100 PR
         3         50 PY
         4        100 PR
         5        200 PY
         6         50 PY

6 rows selected

这是一个存取/款列表。

  • id是唯一列
  • amt列表示每次事务处理(取款或存款)涉及的金额
  • trx列定义了事务处理的类型,取款是"PY",存款是"PR"

现在有一个需求:计算每次存/取款后的余额:如果TRX是"PR",则加上amt值代表的金额,否则要减去amt代表的金额。

怎么做呢?
看下面解决方案:

SQL> with t as
  2   (select 1 as id, 100 as amt, 'PR' as trx
  3      from dual
  4    union all
  5    select 2 as id, 100 as amt, 'PR' as trx
  6      from dual
  7    union all
  8    select 3 as id, 50 as amt, 'PY' as trx
  9      from dual
 10    union all
 11    select 4 as id, 100 as amt, 'PR' as trx
 12      from dual
 13    union all
 14    select 5 as id, 200 as amt, 'PY' as trx
 15      from dual
 16    union all
 17    select 6 as id, 50 as amt, 'PY' as trx
 18      from dual)
 19  select id,
 20         case
 21           when trx = 'PR' then
 22            '存款'
 23           else
 24            '取款'
 25         end as 存取类型,
 26         amt,
 27         sum(case
 28           when trx = 'PR' then
 29            amt
 30           else
 31            -amt
 32         end)over(order by id) as 余额
 33    from t
 34   order by id;

        ID 存取类型        AMT         余额
---------- ---- ---------- ----------
         1 存款        100        100
         2 存款        100        200
         3 取款         50        150
         4 存款        100        250
         5 取款        200         50
         6 取款         50          0

6 rows selected

三、返回各部门工资排名前三位的员工

有经验的人一看到标题,马上就会指出:这个需求太模糊了。为什么?先看下面的示
例。

SQL> select deptno,
  2         empno,
  3         sal,
  4         row_number() over(partition by deptno order by sal desc) as row_number,
  5         rank() over(partition by deptno order by sal desc) as rank,
  6         dense_rank() over(partition by deptno order by sal desc) as dense_rank
  7    from emp
  8   where deptno in (20, 30)
  9   order by 1, 3 desc;

DEPTNO EMPNO       SAL ROW_NUMBER       RANK DENSE_RANK
------ ----- --------- ---------- ---------- ----------
    20  7788   3000.00          1          1          1
    20  7902   3000.00          2          1          1
    20  7566   2975.00          3          3          2
    20  7876   1100.00          4          4          3
    20  7369    800.00          5          5          4
    30  7698   2850.00          1          1          1
    30  7499   1600.00          2          2          2
    30  7844   1500.00          3          3          3
    30  7521   1250.00          4          4          4
    30  7654   1250.00          5          4          4
    30  7900    950.00          6          6          5

11 rows selected

该示例用了PARTITION BY子句,通过这个子句可以把主查询返回的数据分组进行分析。在查询中分别用了三个分析函数ROW_NUMBER、RANK、DENSE_RANK来分组
(PARTITION BY deptno)生成序号。
注意粗体标识的部分,当排序列(工资)有重复数据时,会出现以下情况。
ROW_NUMBER仍然会生成序号1、2、3。

RANK相同的工资会生成同样的序号,而且其后的序号与ROW_NUMBER相同(empno=7566,生成的序号是3)。
DENSE_RANK相同的工资会生成同样的序号,而且其后的序号递增(empno=7566,生成的序号是2)。
这里如果用ROW_NUMBER取排名第一的员工,显然会漏掉7902这名员工。如果用DENSE_RANK取排名前两位的员工,很明显会返回三条记录。所以具体要分析清楚需求,再决定用哪一个函数。
这里选用DENSE_RANK(因需求不定,所以随意选取了一个)取排名前三的员工,返回数据如下:

SQL> select * from (
  2  select deptno,
  3         empno,
  4         sal,
  5         row_number() over(partition by deptno order by sal desc) as row_number,
  6         rank() over(partition by deptno order by sal desc) as rank,
  7         dense_rank() over(partition by deptno order by sal desc) as dense_rank
  8    from emp
  9   where deptno in (20, 30)
 10   order by 1, 3 desc
 11   )where dense_rank<=3;

DEPTNO EMPNO       SAL ROW_NUMBER       RANK DENSE_RANK
------ ----- --------- ---------- ---------- ----------
    20  7788   3000.00          1          1          1
    20  7902   3000.00          2          1          1
    20  7566   2975.00          3          3          2
    20  7876   1100.00          4          4          3
    30  7698   2850.00          1          1          1
    30  7499   1600.00          2          2          2
    30  7844   1500.00          3          3          3

7 rows selected

总结

上面文章是sum()over() 、ROW_NUMBER、RANK、DENSE_RANK几个分析函数常用的场景,这里博主拿了三个工作案例场景给大家讲解。

相关文章
|
5月前
|
SQL 存储 缓存
SQL计算班级语文平均分:详细步骤与技巧
在数据库管理和分析中,经常需要计算某个班级在特定科目上的平均分
|
4月前
|
SQL 监控 安全
员工上网行为监控软件:SQL 在数据查询监控中的应用解析
在数字化办公环境中,员工上网行为监控软件对企业网络安全和管理至关重要。通过 SQL 查询和分析数据库中的数据,企业可以精准了解员工的上网行为,包括基础查询、复杂条件查询、数据统计与分析等,从而提高网络管理和安全防护的效率。
78 0
|
6月前
|
SQL 存储 并行计算
Lindorm Ganos 一条 SQL 计算轨迹
Lindorm Ganos 针对轨迹距离计算场景提供了内置函数 ST_Length_Rows,结合原生时空二级索引和时空聚合计算下推技术,能够高效过滤数据并并行执行运算任务。该方案通过主键索引和时空索引快速过滤数据,并利用多Region并行计算轨迹点距离,适用于车联网等场景。具体步骤包括根据车辆识别代码和时间戳过滤数据、范围过滤轨迹点以及并行计算距离。使用限制包括只支持点类型列聚合运算及表中轨迹点需按顺序排列等。测试结果显示,Lindorm Ganos 在不同数据量下均能实现秒级响应。
56 3
|
7月前
|
SQL 数据挖掘 数据库
SQL计算班级语文平均分:详细步骤与技巧
在数据库管理中,经常需要统计和查询各种汇总信息,如班级某科目的平均分
|
10月前
|
SQL
leetcode-SQL-181. 超过经理收入的员工
leetcode-SQL-181. 超过经理收入的员工
56 0
|
9月前
|
SQL 分布式计算 大数据
MaxCompute产品使用问题之odps sql 底层计算框架是MR吗
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
6月前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
8月前
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
203 13
|
8月前
|
SQL
解锁 SQL Server 2022的时间序列数据功能
【7月更文挑战第14天】要解锁SQL Server 2022的时间序列数据功能,可使用`generate_series`函数生成整数序列,例如:`SELECT value FROM generate_series(1, 10)。此外,`date_bucket`函数能按指定间隔(如周)对日期时间值分组,这些工具结合窗口函数和其他时间日期函数,能高效处理和分析时间序列数据。更多信息请参考官方文档和技术资料。
121 9
|
8月前
|
SQL 存储 网络安全
关系数据库SQLserver 安装 SQL Server
【7月更文挑战第26天】
102 6

热门文章

最新文章