问题描述
我有这样的桌子:
value nextValue
1 2
2 3
3 20
20 21
21 22
22 23
23 NULL
值是按ASC排序的,nextValue是下一行的值。 要求按条件nextValue-value> 10分组,并计算不同组中有多少个值。
例如,应该有两组(1,2,3)
和(20,21,22,23)
,第一组计数为3,第二组计数为4。
我正在尝试用唯一的数字标记每个组,因此我可以按这些标记的数字进行分组
value nextValue mark
1 2 1
2 3 1
3 20 1
20 21 2
21 22 2
22 23 2
23 NULL 2
但是我不知道如何写标记列,nextValue-value>10
时需要一个自增变量。
我可以在Hive中实现它吗?还是有更好的解决方案?
解决方法
计算先前的值,如果value-prev_value> 10,则计算new_group_flag,然后计算new_group_flag的累积总和以获取组号(标记)。最后,您可以使用分析功能或分组依据来计算组计数(在我的示例中,分析计数用于向您显示所有中间计算的完整数据集)。查看代码中的注释。
演示:
with your_data as (--use your table instead of this
select stack(10,--the number of tuples generated
1,2,3,20,21,22,23,40,41,42
) as value
)
select --4. Calculate group count,etc,etc
value,prev_value,new_group_flag,group_number,count(*) over(partition by group_number) as group_count
from
(
select --3. Calculate cumulative sum of new group flag to get group number
value,sum(new_group_flag) over(order by value rows between unbounded preceding and current row)+1 as group_number
from
(
select --2. calculate new_group_flag
value,case when value-prev_value >10 then 1 else 0 end as new_group_flag
from
(
select --1 Calculate previous value
value,lag(value) over(order by value) prev_value
from your_data
)s
)s
)s
结果:
value prev_value new_group_flag group_number group_count
1 \N 0 1 3
2 1 0 1 3
3 2 0 1 3
20 3 1 2 4
21 20 0 2 4
22 21 0 2 4
23 22 0 2 4
40 23 1 3 3
41 40 0 3 3
42 41 0 3 3
,
如果我的理解正确,您可以使用累计金额。这个想法是在next_value - value > 10
时设置一个标志。这标识了组。因此,此查询添加了一个组号:
select t.*,sum(case when nextvalue > value + 10 then 1 else 0 end) over (order by value desc) as mark
from t
order by value;
您可能无法找到令人满意的解决方案,因为编号是按降序排列的。因此,更多的算法修复了该问题:
select t.*,(sum(case when nextvalue > value + 10 then 1 else 0 end) over () + 1 -
sum(case when nextvalue > value + 10 then 1 else 0 end) over (order by value desc)
) as mark
from t
order by value;
Here是db 小提琴。
,这对我有用 在我的情况下,它需要“在前一行和当前行之间无限制的行”。
select t.*,sum(case when nextvalue > value + 10 then 1 else 0 end) over (order by value desc rows between unbounded preceding and current row) as mark
from t
order by value;