有许多类似的问题和答案已经张贴,但我找不到一个与这些差异.1) 零的计数重新开始,2)有一个数学函数应用于被替换的值.

根据客户的日期,事件是否发生(NULL或1).可以假设客户每个日期只有一行.

我想用基于连续零值数量(事件开始时间)的衰减函数替换零值.客户可以每天都参加活动,可以跳过一天,也可以跳过几天.但一旦事件发生,衰退就会重新开始.目前,我的衰减除以2,但这是例如.

DT CUSTOMER EVENT DESIRED
2022-01-01 a 1 1
2022-01-02 a 1 1
2022-01-03 a 1 1
2022-01-04 a 1 1
2022-01-05 a 1 1
2022-01-01 b 1 1
2022-01-02 b 0.5
2022-01-03 b 0.25
2022-01-04 b 1 1
2022-01-05 b 0.5

我可以产生预期的结果,但它非常笨拙.看看是否有更好的方法.这需要扩展到多个事件列.

create or replace temporary table the_data (
  dt date,
  customer char(10),
  event int,
  desired float)
;
insert into the_data values ('2022-01-01', 'a', 1, 1);
insert into the_data values ('2022-01-02', 'a', 1, 1);
insert into the_data values ('2022-01-03', 'a', 1, 1);
insert into the_data values ('2022-01-04', 'a', 1, 1);
insert into the_data values ('2022-01-05', 'a', 1, 1);

insert into the_data values ('2022-01-01', 'b', 1, 1);
insert into the_data values ('2022-01-02', 'b', NULL, 0.5);
insert into the_data values ('2022-01-03', 'b', NULL, 0.25);
insert into the_data values ('2022-01-04', 'b', 1, 1);
insert into the_data values ('2022-01-05', 'b', NULL, 0.5);

with
    base as (
      select * from the_data
    ),
    find_nan as (
      select *, case when event is null then 1 else 0 end as event_is_nan from base
    ),
    find_nan_diff as (
      select *, event_is_nan - coalesce(lag(event_is_nan) over (partition by customer order by dt), 0) as event_is_nan_diff from find_nan
    ),
    find_nan_group as (
      select *, sum(case when event_is_nan_diff = -1 then 1 else 0 end) over (partition by customer order by dt) as nan_group from find_nan_diff
    ),
    consec_nans as (
      select *, sum(event_is_nan) over (partition by customer, nan_group order by dt) as n_consec_nans from find_nan_group
    ),
    decay as (
      select *, case when n_consec_nans > 0 then 0.5 / n_consec_nans else 1 end as decay_factor from consec_nans
    ),
    ffill as (
      select *, first_value(event) over (partition by customer order by dt) as ffill_value from decay
    ),
    final as (
      select *, ffill_value * decay_factor as the_answer from ffill
    )
select * from final
order by customer, dt
;  

谢谢

推荐答案

使用CONDITIONAL_CHANGE_EVENT生成subgrp helper列可以简化查询:

WITH cte AS (
  SELECT *, CONDITIONAL_CHANGE_EVENT(event IS NULL) OVER(PARTITION BY CUSTOMER 
                                                         ORDER BY DT) AS subgrp
  FROM the_data
)
SELECT *, COALESCE(EVENT, 0.5 / ROW_NUMBER() OVER(PARTITION BY CUSTOMER, SUBGRP 
                                                  ORDER BY DT)) AS computed_decay
FROM cte
ORDER BY CUSTOMER, DT;

输出:

enter image description here

Sql相关问答推荐

在数据分区内执行确定

从2个表中查找每条记录的唯一最接近的日期匹配

Group By子句返回太多行

如何在SQL中按每个子组的顺序更新数据?

如何在不更改S代码的情况下,判断存储过程调用了多少次clr函数?

如何在PostgreSQL中对第1,1,1,1,2,2,2,2行进行编号

为什么我的SQL标量函数有时会抛出";子查询返回多个值.这是不允许的.

在Netezza SQL中将字符DataType转换为整型DataType

Haystack针相交-在元素最多的Haystack中查找集合

基于开始/结束日期重叠的BigQuery突发行

使用左外部联接更正列中第+1行的值时重复

如何在 SNOSQL 中执行反连接(或 where 子句过滤)以查找字段不包含另一个表中的值的行?

获取分布在同一行的列中的出现次数

如何在android房间中进行多个加入

替换SQL Server XML中多处出现的 node 值

每次计数器增加时通过运行总重置进行分组

根据潜在空值的条件对记录进行计数

如何获得上个月和下个月之间的销售额差异

过滤具有一对多关系的两个表之间的数据

在 sql 中合并系列以删除重复项