当前日期缺失时的 30 天滚动/移动总和

Posted

技术标签:

【中文标题】当前日期缺失时的 30 天滚动/移动总和【英文标题】:30-day rolling/moving sum when current date is missing 【发布时间】:2016-04-26 10:36:58 【问题描述】:

我有一个表 (view_of_referred_events),它存储给定页面的访问者数量。

date        country_id  referral    product_id  visitors
2016-04-01  216         pl          113759      1
2016-04-03  216         pl          113759      1
2016-04-06  216         pl          113759      13
2016-04-07  216         pl          113759      10

我想计算此产品的 30 天滚动/移动总和,即使是那些缺失的日子。所以最终的结果应该是这样的:

date        country_id  referral    product_id  cumulative_visitors
2016-04-01  216         pl          113759      1
2016-04-02  216         pl          113759      1
2016-04-03  216         pl          113759      2
2016-04-04  216         pl          113759      2
2016-04-05  216         pl          113759      2
2016-04-06  216         pl          113759      15
2016-04-07  216         pl          113759      25

现在,这是一个简单的表示,因为我有几十个不同的 country_idreferralproduct_id。我无法预先创建包含 datecountry_idreferralproduct_id 的所有可能组合的表,因为考虑到表的大小,这将变得无法治疗。如果特定的 datecountry_idreferralproduct_id 以前不存在,我也不想在决赛桌中有一行。

我在想如果view_of_referred_events 当天没有访问者,是否有一种简单的方法告诉 Impala 使用前一行(前一天)的值。

我编写了这个查询,其中list_of_dates 是一个表格,其中包含从 4 月 1 日到 4 月 7 日的日期列表。

select
  t.`date`,
  t.country_id,
  t.referral,
  t.product_id,
  sum(visitors) over (partition by t.country_id, t.referral, t.product_id order by t.`date`
                     rows between 30 preceding and current row) as cumulative_sum_visitors
from (
  selec
    d.`date`, 
    re.country_id, 
    re.referral, 
    re.product_id,
    sum(visitors) as visitors
  from list_of_dates d
  left outer join view_of_referred_events re on d.`date` = re.`date`
    and re.referral = "pl"
    and re.product_id = "113759"
    and re.country_id = "216"
  group by d.`date`, re.country_id, re.referral, re.product_id
  ) t
order by t.`date` asc;

这会返回类似于我想要的东西,但不完全一样。

date        country_id  referral    product_id  cumulative_visitors
2016-04-01  216         pl          113759      1
2016-04-02  NULL        NULL        NULL        NULL
2016-04-03  216         pl          113759      2
2016-04-04  NULL        NULL        NULL        NULL
2016-04-05  NULL        NULL        NULL        NULL
2016-04-06  216         pl          113759      15
2016-04-07  216         pl          113759      25

【问题讨论】:

请澄清:您的文字和标题是关于累积的。该查询建议您需要 30 天的滚动/移动总和。 【参考方案1】:

我添加了另一个子查询来获取分区中最后一行的值。我不确定您使用的是哪个版本的 hive/impala,last_value(column_name, ignore null values true/false) 是语法。

我假设您正在尝试查找 30 天(月)内的累积计数,我建议使用月字段对行进行分组。月份可以来自您的维度表list_of_dates 或仅来自substr(date, 1, 7),并获得超过..rows unbounded preceding and current row 的访问者的累积计数。

查询:

select
  `date`,
  country_id,
  referral,
  product_id,
  sum(visitors) over (partition by country_id, referral, product_id order by `date`
                     rows between 30 preceding and current row) as cumulative_sum_visitors 
from (select
  t.`date`,
  -- get the last not null value from the partition window w for country_id, referral & product_id
  last_value(t.country_id, true) over w as country_id,
  last_value(t.referral, true) over w as  referral
  last_value(t.product_id, true) over w as product_id 
  if(visitors = null, 0, visitors) as visitors 
from (
  select
    d.`date`, 
    re.country_id, 
    re.referral, 
    re.product_id,
    sum(visitors) as visitors
  from list_of_dates d
  left outer join view_of_referred_events re on d.`date` = re.`date`
    and re.referral = "pl"
    and re.product_id = "113759"
    and re.country_id = "216"
  group by d.`date`, re.country_id, re.referral, re.product_id
  ) t
window w as (partition by t.country_id, t.referral, t.product_id order by t.`date`
                     rows between unbounded preceding and unbounded following)) t1
order by `date` asc;

【讨论】:

很遗憾,当前版本的 Impala 不支持在 LAST_VALUE 函数中忽略 NULL 值。【参考方案2】:

我不确定性能会有多好,但您可以通过将数据聚合两次并为第二次聚合增加 30 天并否定计数来做到这一点。

类似这样的:

with t as (
      select d.`date`, re.country_id, re.referral, re.product_id,
             sum(visitors) as visitors
      from list_of_dates d left outer join
           view_of_referred_events re
           on d.`date` = re.`date` and
              re.referral = 'pl' and
              re.product_id = 113759 and
              re.country_id = 216
      group by d.`date`, re.country_id, re.referral, re.product_id
     )
select date, country_id, referral, product_id,
       sum(sum(visitors)) over (partition by country_id, referral, product_id order by date) as visitors
from ((select date, country_id, referral, product_id, visitors
       from t
      ) union all
      (select date_add(date, 30), country_id, referral, product_id, -visitors
       from t
      ) 
     ) tt
group by date, country_id, referral, product_id;

【讨论】:

我认为您在定义 t 时忘记了 GROUP BY d.date, re.country_id, re.referral, re.product_id。除此之外,此查询不会继承没有访问者的那些日子的值。事实上,在那些日子里,country_idreferralproduct_idvisitors 的值将是 NULL @Gianluca 。 . .谢谢你。至于第二点,我以为你想要没有变化的日子。

以上是关于当前日期缺失时的 30 天滚动/移动总和的主要内容,如果未能解决你的问题,请参考以下文章

如何获得当前日期前 30 天?

SQL数据库怎么查询,between 当前日期 and 当前日期前30天,之间的数据

如何在codeigniter的当前日期插入天间隔?

oracle 日期函数当前日期的前30天的日期

jquery 如何用函数比较日期相差30天

用代码实现使当前日期 Date型的数据增加一个月