一次ORACLE OVER()开窗函数的使用经历

前景:有一张标的表(loan),用户每做一笔借款请求,都会产生一条记录,每一条借款记录都会有一个状态。比如CLOSED(已结标),IN_PROPRESS(还款中),READY(已满标),FAILED(已流标),每一条记录都是一个“标的”。每一个标的有一个唯一的id,是标的表的主键,同时还有一个borrower_id,代表借贷人。同一个借贷人,可以有多笔借贷。

然后我编写sql想要实现的目标(需求)是:取出标的表的每一条记录,同时再加一个字段,这个字段是一个记录数,记录的这个标的对应的borrower_id对应的用户在标的表里的记录数,这个记录数有个条件:
loan.loan_status IN (‘OPEN’,’READY’,’IN_PROGRESS’,’OVER_DUE’,’READY_HF_CON’)

这里取出的每一条标的记录都是单独的,但是要count()的记录并不是唯一的,听别人说要用开窗函数。那么我就来用一下!

这是我第一次写的SQL:

SELECT l.id AS "id", l.loan_title AS "loanTitle",
l.contact_amount AS "contactAmount", l.interest AS "interest", 
l.loan_status AS "loanStatus",
l.loan_months AS "loanMonths", l.finished_ratio AS "finishedRatio",l.create_time AS "createTime",
COUNT(0) OVER() AS "noPayOff"
FROM loan l, user_info ui
WHERE l.borrower_id = ui.user_id AND l.loan_status IN ('OPEN','READY','IN_PROGRESS','OVER_DUE','READY_HF_CON')
ORDER BY l.id DESC

这里写图片描述

加粗的那段代表了把count()函数开窗了。。。因为count()只能返回一条,只有一个具体值,但是我前半段sql返回是多条记录,因为一条对多条,需要开窗。(好像很6的样子。。。,谁叫我菜呢,第一次听说。。。)

可以看到,noPayOff字段显示的是5293,且所有记录一样,代表记录数。

但是这并不是我想要的,我要的count() 是count同一个borrower_id在标的表的记录数,即count(borrower_id)。于是我写了

SELECT l.id AS "id", l.loan_title AS "loanTitle",
l.contact_amount AS "contactAmount", l.interest AS "interest", 
l.loan_status AS "loanStatus",l.borrower_id, 
l.loan_months AS "loanMonths", l.finished_ratio AS "finishedRatio",l.create_time AS "createTime",
COUNT(*) OVER(PARTITION BY l.borrower_id) AS "noPayOff"
FROM loan l, user_info ui
WHERE l.borrower_id = ui.user_id AND l.loan_status IN ('OPEN','READY','IN_PROGRESS','OVER_DUE','READY_HF_CON')
ORDER BY l.id DESC

此处PARTITION BY l.borrower_id 代表的是以borrower_id来分割,划分,效果类似GROUP BY

运行结果如图所示:

这里写图片描述

好像有点对了。。。
那么我们来验证一下

第一条.

SELECT COUNT(*) FROM loan l, user_info ui
WHERE l.borrower_id = ui.user_id AND l.loan_status IN ('OPEN','READY','IN_PROGRESS','OVER_DUE','READY_HF_CON')
AND l.borrower_id = 2802509
ORDER BY l.id DESC

运行结果:

这里写图片描述

第二条.

SELECT COUNT(*) FROM loan l, user_info ui
WHERE l.borrower_id = ui.user_id AND l.loan_status IN ('OPEN','READY','IN_PROGRESS','OVER_DUE','READY_HF_CON')
AND l.borrower_id = 1574561
ORDER BY l.id DESC

这里写图片描述

第十二条.

SELECT COUNT(*) FROM loan l, user_info ui
WHERE l.borrower_id = ui.user_id AND l.loan_status IN ('OPEN','READY','IN_PROGRESS','OVER_DUE','READY_HF_CON')
AND l.borrower_id = 1800626
ORDER BY l.id DESC

这里写图片描述

好了,3条已经验证完了,已经不会有错了。(就是这么严谨)

然而你以为到了这里问题结束了吗。。。并没有,我发现我把我需要统计的数据的条件写在了sql的最后面
AND l.loan_status IN (‘OPEN’,’READY’,’IN_PROGRESS’,’OVER_DUE’,’READY_HF_CON’)。这样会产生什么问题呢?让我们再来看一下需求,我需要的是所有的数据数,并且统计loan_status满足条件的列。比如,我有两条数据,一条是满足count的筛选条件的,一条不满足,我只需要统计满足条件的那一条,但是另一条数据我也会要显示出来,如果不满足统计条件,那就置为0好了。

然后我又写了:

SELECT l.id AS "id", l.loan_title AS "loanTitle", l.contact_amount AS "contactAmount",
l.interest AS "interest", l.loan_status AS "loanStatus", 
l.loan_months AS "loanMonths", l.create_time AS "createTime", l.borrower_id, 

COUNT(
CASE WHEN l.loan_status IN ('OPEN','READY','IN_PROGRESS','OVER_DUE','READY_HF_CON') 
THEN 1 
ELSE 0
END)

OVER(PARTITION BY l.borrower_id) AS "noPayOff"
FROM loan l, user_info ui
WHERE l.borrower_id = ui.user_id
ORDER BY l.id DESC

运行结果如图所示:

这里写图片描述

我在count里面加了一个判断条件,意思就是当记录满足条件时才计数,其他就不管。

然而好像记录数比之前多了。。。问了一个专门做连线的朋友也并没有发现问题的所在,后来还是我机智,发现 count(1), count(0), count(*) 好像在这里效果都一样啊。。。囧,这种小错误

最后的sql:

SELECT l.id AS "id", l.loan_title AS "loanTitle", l.contact_amount AS "contactAmount",
l.interest AS "interest", l.loan_status AS "loanStatus", 
l.loan_months AS "loanMonths", l.create_time AS "createTime", l.borrower_id, 

COUNT(
CASE WHEN l.loan_status IN ('OPEN','READY','IN_PROGRESS','OVER_DUE','READY_HF_CON') 
THEN 1
END)

OVER(PARTITION BY l.borrower_id) AS "noPayOff"
FROM loan l, user_info ui
WHERE l.borrower_id = ui.user_id
ORDER BY l.id DESC

运行结果如图所示:

这里写图片描述

简单粗暴,case里面只管满足的,不满足的就直接end,大概就是不做计数吧,好像不做计数的话,这个函数默认初始值是0。

好了,大功告成!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值