• sql计算占比


    计算占比是日常分析中常见的需求,下面我们来小结一下怎么用sql来实现计算占比。

    1.数据准备

    现在有一张表,表里有两个字段,op_name与state,都为离散型可枚举数据,除此以外表里还有其他字段。数据形式如下

    op_name	state	c1	c2
    n1	s1	...
    n2 	s2	...
    n1	s3	...
    n3	s2	...
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.计算某个字段各枚举值占比

    以上面的数据表为,我们想计算state字段各状态占比,可以有如下写法

    
    SELECT state, count(*) as state_num, round(
    count(*) / SELECT count(*) from xxx , 5) as percentage_of_state
    from xxx
    group by state
    with rollup
    order by percentage_of_state DESC
    limit 200;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    最终实际业务表上返回结果为

    null	67264089	1
    s1	37465212	0.55699
    s2	22699606	0.33747
    s3	6953280	0.10337
    s4	124627	0.00185
    s5	15030	0.00022
    s6	6334	0.00009
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    因为要计算占比,肯定需要计算总数。在上面的代码中,我们使用了一个子查询,先计算出数据总量,然后根据state字段再分组,计算各state状态值的占比。

    3.更复杂的分组占比

    上面求的占比比较简单,只跟state字段有关。
    如果我们提升一下难度,想计算每个op_name中state占比该如何处理?
    更具像一点就是:
    假设op_name字段有一个值为n1,n1对应的state有三种状态s1, s2, s3,现在想计算出在所有n1中,s1, s2, s3的占比。

    可以按照如下思路实现

    首先,要计算op_name中state占比,肯定需要先对op_name进行分组,计算各op_name的总量。
    其次,还需要对op_name,state进行联合分组,这样才能得到占比中的分子。
    最后,分子分母都计算出来了,根据op_name进行join,就可以计算出占比。

    SELECT a.op_name, a.state, a.state_count, a.state_count/op_count from
    (SELECT op_name, state, count(*) as state_count  from xxx
    group by op_name, state)a
    join
    (SELECT op_name, count(*) as op_count from xxx
    group by op_name)b
    on a.op_name = b.op_name
    order by op_name desc
    limit 20;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    将上述代码在实际业务表中运行,计算得出的结果如下。

    n1	s1	5738	0.94468225
    n1	s2	308	0.05070794
    n1	s3	28	0.00460981
    n2	s1	208	0.28108108
    n2	s2	170	0.22972973
    n2	s3	362	0.48918919
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.使用分组函数计算占比

    上面join的方式可以计算出结果,但是代码显得稍微麻烦了点。有没有更简洁的方式?
    答案是有的,我们可以使用窗口函数达到同样的效果。

    首先我们先简单看下窗口函数的定义与语法

    OVER用于为行定义一个窗口,它对一组值进行操作,不需要使用GROUP BY子句对数据进行分组,能够在同一行中同时返回基础行的列和聚合列。

    OVER ( [ PARTITION BY column ] [ ORDER BY culumn ] )
    
    • 1

    其中,PARTITION BY 用来对子句进行分组,而order by则是对子句进行排序使用。

    OVER()指定了分组的行,不使用group by就可以达到对数据分组的目的,还可以返回基础列与聚合列。

    OVER窗口函数必须与聚合函数或者排序函数一起使用。聚合函数比如SUM, MAX, MIN, AVG,COUNT等,而排序函数有RANK, ROW_NUMBER,NTILE等。

    回到上面的需求,我们可以有如下解法

    SELECT op_name, state, state_count, state_count / sum(state_count) over(PARTITION BY op_name) as ratio from
    (SELECT op_name, state, count(*) as state_count  from xxx
    group by op_name, state)a
    order by op_name desc
    limit 20;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    上面用一个子查询就解决了前面的问题。子查询对op_name, state进行了联合分组,然后窗口函数中对op_name进行分组并对state_count进行求和操作,就得到了op_name的总数,即计算占比的分母。

    最后的结果,与前面的join结果一样。

    n1	s1	5738	0.94468225
    n1	s2	308	0.05070794
    n1	s3	28	0.00460981
    n2	s1	208	0.28108108
    n2	s2	170	0.22972973
    n2	s3	362	0.48918919
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    性价比比苹果HomeKit高的智汀Smart Assistant全方位指南
    画程序流程图
    图像处理中几何畸变校正,图像纠正的方法有哪些
    VR全景拍摄为什么要加盟?巧借资源实现共赢
    为什么要写单测
    Shiro的实现机制(源码解析)
    拿走不谢,孕妈想知道的都在这里了,关于分娩前见红
    Java 性能优化实战案例分析:常见 Java 代码优化法则
    ROS自学笔记十七:Arbotix
    分布式机器学习:异步SGD和Hogwild!算法(Pytorch)
  • 原文地址:https://blog.csdn.net/bitcarmanlee/article/details/127997471