sql计算占比

Posted bitcarmanlee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
...

以上是关于sql计算占比的主要内容,如果未能解决你的问题,请参考以下文章

SQL的update语句中,可以让要update的表里的数据与另外的一个表里的数据进行运算吗

计算双精度分子和分母的最准确方法

如何把SQL server 表里插入转换科学计数法的方法。

如何在sql数据库表里加入新的一列(表里原有数据)

请问SQL如何实现批量查询

如何在sql数据库表里加入新的一列(表里原有数据)