如何用trino或impala在window函数中添加条件分区?

How to add conditional partition in a window function with trino or impala?

例如,我有如下数据集:

time action
03:00:00 block
04:00:00 unblock
05:00:00 block
06:00:00 unblock
07:00:00 unblock
08:00:00 block

现在对于每一行,我想获取列 action 等于当前行时间之前的“块”的最后时间 。例如,对于time等于“07:00:00”且action等于“unblock”的第五行,最后一次action等于“block”应该是第三行,预计时间是“05:00:00”。

我的最终预期结果是:

time action last_time
03:00:00 block 03:00:00
04:00:00 unblock 03:00:00
05:00:00 block 05:00:00
06:00:00 unblock 05:00:00
07:00:00 unblock 05:00:00
08:00:00 block 08:00:00

如何使用 window 函数 而不通过自身加入 来获得上述结果?

(p.s。如果不能达到上面的结果,下面的输出也可以:

time action last_time
03:00:00 block NULL
04:00:00 unblock 03:00:00
05:00:00 block 03:00:00
06:00:00 unblock 05:00:00
07:00:00 unblock 05:00:00
08:00:00 block 05:00:00

一旦我们确定 action = 'block' 应该开始一个新的块并且我们识别了这些块 (block_no),我们就可以使用 window 由 block_no 分区的函数] 找到每个块中的最小值 time

如果时间不是单调递增,我们可以使用FIRST_VALUE window函数代替,如果我们有另一种排序方式,或者只是使用另一个case表达式来获取时间只有当action = 'block',这将使其他行保留为空,这很容易通过 MAX/MIN/etc.

忽略

然而,根据当前数据,我认为我们无法绕过这样的假设,即对于每个块之间的所有行,时间需要单调增加或至少从块到块增加。

试试这个:

The fiddle

WITH cte1 AS (
         SELECT *, SUM(CASE WHEN action = 'block' THEN 1 END) OVER (ORDER BY time) AS block_no FROM test
     )
SELECT *, MIN(time) OVER (PARTITION BY block_no) AS block_time FROM cte1
 ORDER BY time
;

结果:

time action block_no block_time
03:00:00 block 1 03:00:00
04:00:00 unblock 1 03:00:00
05:00:00 block 2 05:00:00
06:00:00 unblock 2 05:00:00
07:00:00 unblock 2 05:00:00
08:00:00 block 3 08:00:00

设置:

CREATE TABLE test (time varchar(20), action  varchar(20));

INSERT INTO test VALUES
  ('03:00:00', 'block')
, ('04:00:00', 'unblock')
, ('05:00:00', 'block')
, ('06:00:00', 'unblock')
, ('07:00:00', 'unblock')
, ('08:00:00', 'block')
;