一条SQL实现数值占比计算,拒绝嵌套查询
提示:在日常的工作项目中,会有需要获取数值占比计算的需求,我们改如何给他做到通用简洁化呢?
我们一般的项目中往往会选择再一次嵌套查询去计算占比值,但是如果我们的项目中需要进行配置、通用起来的情况下,会给我们造成很大的困扰。
前言
提示:
为此,我考虑不以嵌套的形式,一条sql直接输出我们想要的数值占比,通过只需改变字段名称,就可直接获取占比值,一并返回,实现我们的高可用。
提示:以下是本篇文章正文内容,下面案例可供参考
一、通过with rollup函数,进行小计,而后取最后一个值,获取总数。
支持多种数据库,oracle 、vertica ,因其中涉及窗口函数,mysql得在8.0以上的版本。
以下是mysql案例介绍。
--只针对mysql8.0以上版本,其余数据库正常使用
select id ,
count(1) as count,
concat(round(cast(count(1) /
last_value(count(1))
over (order by count(1) rows between unbounded PRECEDING AND unbounded FOLLOWING) as FLOAT) *
100, 2), '%') as radio
from user
where id in (1, 2, 3)
group by id
with rollup;
解析:我以USER表为例,首先通过分组获取每组count的值,然后通过with rollup函数 获取 (总计),
在通过last_value() over()函数去获取最后一个总计的数值,最后就是一些计算百分比的函数进行返回
注:last_value 函数是对某个字段往下取值 over() 中 rows between unbounded PRECEDING AND unbounded FOLLOWING ;
说明:这是窗口函数,PRECEDING 意为 从第几个开始,FOLLOWING 偏移量是多少。
例 rows between 1 PRECEDING AND 2 FOLLOWING 从第一个值往下走两步,也是是第三列的值。
unbounded 是无界限的意思,
如果单是 unbounded PRECEDING 则就是取第一个值。联合起来也就是上的案例取最后一个值。
针对其他数据库,考虑with rollup替换。例 :vertica 替换为 rollup
二、使用sum() over()高级函数。
需求:统计学生某时间段内,学生阅读了多少本图书及其所有在所有学生中阅读的占比。
直接上例子。
select
name 学生名称,
sum(read_book) 各学生阅读数,
sum(sum(read_book)) over(order by read_book desc rows between unbounded PRECEDING AND unbounded FOLLOWING) 所有学生阅读数 //占比率两者相除即可
from user
group by name //学生名称分组
适用范围:mysql8.0及以上,oracle、vertica等。