在 Postgresql 中为每个拒绝或接受日期查找第一个 OPENED_DATE
Find first OPENED_DATE for every Denied or Accepted date in Postgresql
我需要找到请求的第一个文档打开日期。对于每个请求,第一步是打开一个文档,然后可以多次拒绝或接受它。我需要在拒绝日期和接受日期之间找到第一个 open_date。我尝试了 LEAD
函数,但它找到了最近的一个。
我的 table 如下所示:
id | document_id | oper_name | created_at |
--------------------------------------------------------------------
24 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:40:18 |
25 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:40:19 |
27 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:40:27 |
28 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:40:31 |
29 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:42:16 |
30 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:45:01 |
31 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:48:30 |
32 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 12:34:16 |
33 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 13:12:01 |
34 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 13:42:23 |
35 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 14:40:23 |
36 | 102 | DOCUMENT_IS_ACCEPTED| 2020-07-06 15:48:30 |
37 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 16:20:45 |
38 | 102 | DOCUMENT_IS_DENY | 2020-07-06 16:41:30 |
我的结果应该如下所示:
id | document_id | oper_name | created_at | open_date | parnt_id
28 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:40:31 | 2020-07-06 11:40:18 | 24
31 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:48:30 | 2020-07-06 11:42:16 | 29
36 | 102 | DOCUMENT_IS_ACCEPTED| 2020-07-06 15:48:30 | 2020-07-06 12:34:16 | 32
38 | 102 | DOCUMENT_IS_DENY | 2020-07-06 16:41:30 | 2020-07-06 16:20:45 | 37
我尝试了下面的查询,但它并没有像我想要的那样工作
select * from (
select id,document_id,event_type,created_at,
LEAD(created_at,-1) OVER (ORDER BY created_at asc) as open_date
from table where document_id = 102 order by created_at asc
) s where event_type in ('DOCUMENT_IS_DENY','DOCUMENT_IS_ACCEPTED')
这看起来像是一个缺口和孤岛问题。这是一种方法:
select document_id,
max(id) filter(where rn_desc = 1) as id,
max(oper_name) filter(where rn_desc = 1) as oper_name,
max(created_at) as created_at,
min(created_at) as open_date,
max(id) filter(where rn_asc = 1) as parent_id
from (
select t.*,
row_number() over(partition by document_id, grp order by created_at) rn_asc,
row_number() over(partition by document_id, grp order by created_at desc) rn_desc
from (
select t.*,
count(*) filter(where oper_name <> 'DOCUMENT_IS_OPENED') over(partition by document_id order by created_at desc) grp
from mytable t
) t
) t
where 1 in (rn_asc, rn_desc)
group by document_id, grp
order by document_id, id
我们的想法是将记录分组(岛屿),其中每个组都以非开场动作结束。我们如何定义组:使用从 table 中的最新日期开始并向后计算的未打开操作计数。然后,我们可以使用window函数来识别每个岛的起点和终点,并通过条件聚合展示我们感兴趣的列。
document_id | id | oper_name | created_at | open_date | parent_id
----------: | -: | :------------------- | :------------------ | :------------------ | --------:
102 | 28 | DOCUMENT_IS_DENY | 2020-07-06 11:40:31 | 2020-07-06 11:40:18 | 24
102 | 31 | DOCUMENT_IS_DENY | 2020-07-06 11:48:30 | 2020-07-06 11:42:16 | 29
102 | 36 | DOCUMENT_IS_ACCEPTED | 2020-07-06 15:48:30 | 2020-07-06 12:34:16 | 32
102 | 38 | DOCUMENT_IS_DENY | 2020-07-06 16:41:30 | 2020-07-06 16:20:45 | 37
我需要找到请求的第一个文档打开日期。对于每个请求,第一步是打开一个文档,然后可以多次拒绝或接受它。我需要在拒绝日期和接受日期之间找到第一个 open_date。我尝试了 LEAD
函数,但它找到了最近的一个。
我的 table 如下所示:
id | document_id | oper_name | created_at |
--------------------------------------------------------------------
24 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:40:18 |
25 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:40:19 |
27 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:40:27 |
28 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:40:31 |
29 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:42:16 |
30 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:45:01 |
31 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:48:30 |
32 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 12:34:16 |
33 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 13:12:01 |
34 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 13:42:23 |
35 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 14:40:23 |
36 | 102 | DOCUMENT_IS_ACCEPTED| 2020-07-06 15:48:30 |
37 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 16:20:45 |
38 | 102 | DOCUMENT_IS_DENY | 2020-07-06 16:41:30 |
我的结果应该如下所示:
id | document_id | oper_name | created_at | open_date | parnt_id
28 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:40:31 | 2020-07-06 11:40:18 | 24
31 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:48:30 | 2020-07-06 11:42:16 | 29
36 | 102 | DOCUMENT_IS_ACCEPTED| 2020-07-06 15:48:30 | 2020-07-06 12:34:16 | 32
38 | 102 | DOCUMENT_IS_DENY | 2020-07-06 16:41:30 | 2020-07-06 16:20:45 | 37
我尝试了下面的查询,但它并没有像我想要的那样工作
select * from (
select id,document_id,event_type,created_at,
LEAD(created_at,-1) OVER (ORDER BY created_at asc) as open_date
from table where document_id = 102 order by created_at asc
) s where event_type in ('DOCUMENT_IS_DENY','DOCUMENT_IS_ACCEPTED')
这看起来像是一个缺口和孤岛问题。这是一种方法:
select document_id,
max(id) filter(where rn_desc = 1) as id,
max(oper_name) filter(where rn_desc = 1) as oper_name,
max(created_at) as created_at,
min(created_at) as open_date,
max(id) filter(where rn_asc = 1) as parent_id
from (
select t.*,
row_number() over(partition by document_id, grp order by created_at) rn_asc,
row_number() over(partition by document_id, grp order by created_at desc) rn_desc
from (
select t.*,
count(*) filter(where oper_name <> 'DOCUMENT_IS_OPENED') over(partition by document_id order by created_at desc) grp
from mytable t
) t
) t
where 1 in (rn_asc, rn_desc)
group by document_id, grp
order by document_id, id
我们的想法是将记录分组(岛屿),其中每个组都以非开场动作结束。我们如何定义组:使用从 table 中的最新日期开始并向后计算的未打开操作计数。然后,我们可以使用window函数来识别每个岛的起点和终点,并通过条件聚合展示我们感兴趣的列。
document_id | id | oper_name | created_at | open_date | parent_id ----------: | -: | :------------------- | :------------------ | :------------------ | --------: 102 | 28 | DOCUMENT_IS_DENY | 2020-07-06 11:40:31 | 2020-07-06 11:40:18 | 24 102 | 31 | DOCUMENT_IS_DENY | 2020-07-06 11:48:30 | 2020-07-06 11:42:16 | 29 102 | 36 | DOCUMENT_IS_ACCEPTED | 2020-07-06 15:48:30 | 2020-07-06 12:34:16 | 32 102 | 38 | DOCUMENT_IS_DENY | 2020-07-06 16:41:30 | 2020-07-06 16:20:45 | 37