SQL - 为每个 ID 创建时间线 (Vertica)

SQL - Creating a timeline for each ID (Vertica)

我在 SQL(使用 Vertica)中处理以下问题:

简而言之 -- 为每个 ID 创建一个时间线(在 table 中,我有多行,在我的示例中,每个 ID 都有订单)

我想要实现的目标 -- 我有一个 table 历史订单日期,我想计算新客户(第一个订单)在过去一个月)、活跃客户(过去 1-3 个月内 >1 个订单)、被动客户(过去 3-6 个月没有订单)和不活跃客户(>6 个月没有订单)费率。

到目前为止我采取了哪些步骤 -- 我能够构建一个类似于下面示例的 table:

CustomerID  Current order date  Time between current/previous order First order date (all-time) 
001         2015-04-30 12:06:58 (null)                              2015-04-30 12:06:58
001         2015-09-24 17:30:59 147 05:24:01                        2015-04-30 12:06:58
001         2016-02-11 13:21:10 139 19:50:11                        2015-04-30 12:06:58
002         2015-10-21 10:38:29 (null)                              2015-10-21 10:38:29
003         2015-05-22 12:13:01 (null)                              2015-05-22 12:13:01
003         2015-07-09 01:04:51 47 12:51:50                         2015-05-22 12:13:01
003         2015-10-23 00:23:48 105 23:18:57                        2015-05-22 12:13:01

一点直觉:客户 001 下了三个订单,第二个订单距第一个订单 147 天。客户002总共只下了一个订单。

我认为下一步应该是什么 -- 我想知道每个日期(还有某个用户没有下订单的日期),对于每个 CustomerID,自 his/her 上次下单以来已有多长时间。这意味着我将为每个 CustomerID 创建某种时间线。在上面给出的示例中,我将为每个 CustomerID 获得 287(2015 年 5 月 1 日至 2016 年 2 月 11 日之间的天数,table 的时间跨度)行。 我很难解决上一步。当我执行了这一步后,我想创建一个字段,在每个日期显示最后一个订单日期、最后一个订单日期和当前订单日期之间的时间段日期,以及某人在当前日期所处的状态。对于前面介绍的示例,这看起来像这样:

CustomerID Last order date     Current date        Time between current date /last order State
001        2015-04-30 12:06:58 2015-05-01 00:00:00 0 00:00:00                            New
...
001        2015-04-30 12:06:58 2015-06-30 00:00:00 60 11:53:02                           Active
...
001        2015-09-24 17:30:59 2016-02-01 00:00:00 129 11:53:02                          Passive
...

...
002        2015-10-21 17:30:59 2015-10-22 00:00:00 0 06:29:01                            New
...
002        2015-10-21 17:30:59 2015-11-30 00:00:00 39 06:29:01                           Active
...

...
003        2015-05-22 12:13:01 2015-06-23 00:00:00 31 11:46:59                           Active
...
003        2015-07-09 01:04:51 2015-10-22 00:00:00 105 11:46:59                          Inactive
...    

在点处应该有所有中间日期但是为了space我把这些从table.

当我知道每个日期的每个客户的状态时 (active/passive/inactive),我的计划是按日期对状态和分组求和,这应该给我新的、活跃的、被动的和不活跃的总和顾客。从这里开始,我可以轻松计算每个日期的费率。

有人知道我怎样才能完成这个任务吗?

注意 -- 如果有人对如何实现上述目标有其他想法(与我想到的方法相比使用其他方法)请告诉我!

编辑

假设你从这样的 table 开始:

SQL> select * from ord order by custid, ord_date ;
 custid |      ord_date       
--------+---------------------
      1 | 2015-04-30 12:06:58
      1 | 2015-09-24 17:30:59
      1 | 2016-02-11 13:21:10
      2 | 2015-10-21 10:38:29
      3 | 2015-05-22 12:13:01
      3 | 2015-07-09 01:04:51
      3 | 2015-10-23 00:23:48
(7 rows)

您可以使用 Vertica 的时间序列分析函数 TS_FIRST_VALUE()、TS_LAST_VALUE() 来填补空白并将 last_order 日期插入当前日期:

然后您只需将此与从同一 table 生成的 Vertica TimeSeries 结合起来,间隔一天从每个客户下 his/her 第一个订单到现在的第一天开始(current_date):

select 
    custid, 
    status_dt,
    last_order_dt,
    case 
        when status_dt::date - last_order_dt::date < 30 then case
            when nord = 1 then 'New' else 'Active' end
        when status_dt::date - last_order_dt::date < 90 then 'Active'
        when status_dt::date - last_order_dt::date < 180 then 'Passive'
        else 'Inactive'
    end as status
from ( 
    select 
        custid,
        last_order_dt,
        status_dt,
        conditional_true_event (first_order_dt is null or
                                last_order_dt > lag(last_order_dt))
            over(partition by custid order by status_dt) as nord
    from (
        select 
            custid, 
            ts_first_value(ord_date) as first_order_dt ,
            ts_last_value(ord_date) as last_order_dt ,
            dt::date as status_dt
        from 
            ( select custid, ord_date from ord 
              union all
              select distinct(custid) as custid, current_date + 1 as ord_date from ord
            ) z timeseries dt as '1 day' over (partition by custid order by ord_date)
         ) x
      ) y
where status_dt <= current_date
order by 1, 2
;

你会得到这样的东西:

   custid | status_dt  |    last_order_dt    | status  
  --------+------------+---------------------+---------
        1 | 2015-04-30 | 2015-04-30 12:06:58 | New
        1 | 2015-05-01 | 2015-04-30 12:06:58 | New
        1 | 2015-05-02 | 2015-04-30 12:06:58 | New
        ...
        1 | 2015-05-29 | 2015-04-30 12:06:58 | New
        1 | 2015-05-30 | 2015-04-30 12:06:58 | Active
        1 | 2015-05-31 | 2015-04-30 12:06:58 | Active
        ...
        etc.