sql计算占比

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

1.数据准备

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

op_name	state	c1	c2
n1	s1	...
n2 	s2	...
n1	s3	...
n3	s2	...
...

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;

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

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

因为要计算占比,肯定需要计算总数。在上面的代码中,我们使用了一个子查询,先计算出数据总量,然后根据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;

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

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
...

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

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

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

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

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

其中,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;

上面用一个子查询就解决了前面的问题。子查询对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
...
  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值