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.
我在 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.