我有一份客户通过工作流程的日志。我想做两件事,我正在努力解决其中任何一件事。
首先是:我希望过滤掉在工作流程开始时输入第一个状态而未启动的客户(输入状态0)。
其次是:对于剩下的客户,我想知道他们在工作流程的每一步中花了多少时间。
每条记录都有:
我尝试进行一个查询,这样我就可以获得按客户和状态分组的进入和退出时间戳,如下所示:
SELECT
CUSTOMER_ID,
STATE,
MIN(UPDATE_DT) AS ENTRY_DATE,
MAX(UPDATE_DT) AS EXIT_DATE
FROM LOG_DATA
GROUP BY CUSTOMER_ID, STATE
ORDER BY CUSTOMER_ID, STATE;
但我立即遇到了一些问题。查询运行得很好但是:
我试图通过在我的选择中引入一个额外的属性来专注于第一个问题:
MIN(STATE) OVER(PARTITION BY CUSTOMER_ID) AS EARLIEST_STATE
但后来遇到了一些问题。我无法将EARLIEST_STATE包含为WHERE或GROUP BY HAVING的条件,因为WHERE它不存在,GROUP BY将不允许我包含EARLIEST_STATE。
正如我认为通过它变得更糟--MIN(STATE)只能证明,客户最多只能获得STATE = 0但不是说他们有一条记录表示ACTION =“enter”且STATE = 0。所以这种方法失败不仅因为我无法让它运行,而且因为它在逻辑上也不正确。
我知道我可以用SELECT做多个SELECT,但这感觉很笨,我想学习正确的方法来做到这一点。我处理1000万行数据也没有帮助,因此效率很重要。
我正在使用Postgres 9.5,在这种情况下,我无法控制数据库技术或数据架构。
这会很慢,但我可以使用我的Python来做这件事,但我真的想知道使用数据库执行此操作的正确方法。
答案 0 :(得分:0)
如果我理解正确,您希望对于结果集中的任何客户,至少有一行Action = 'Enter'
和state = 0
。这表明了一个窗口函数:
SELECT CUSTOMER_ID, STATE,
MIN(UPDATE_DT) AS ENTRY_DATE,
MAX(UPDATE_DT) AS EXIT_DATE,
FROM (SELECT l.*,
SUM(CASE WHEN ACTION = 'Enter' AND state = 0 THEN 1 ELSE 0 END) OVER (PARTITION BY CUSTOMER_ID) as num_validenter
FROM LOG_DATA l
) l
WHERE num_validenter > 0
GROUP BY CUSTOMER_ID, STATE
ORDER BY CUSTOMER_ID, STATE