I need to find first document open date for request. For every request first step is opening a document and then it can be denied or accepted multiple times. I need to find first open_date between deny and accept dates. I tried LEAD
function but it finds nearest one.
My table looks like below:
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 |
My result should look like below:
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
I tried below query but it does not work like I want
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')
Advertisement
Answer
This reads like a gaps-and-islands problem. Here is one approach:
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
The idea is to put records in groups (the islands), where each group ends with a non-opening action. How do we define the groups: with a count of non-opening actions that starts from the latest date in the table and goes backwards. Then, we can use window funtions to identify the start and end of each island, and exhibit the columns we are interested it with conditional aggregation.
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