SQL查询将更改日志转换为间隔

时间:2018-12-11 14:43:45

标签: sql postgresql select

所以让我描述一下问题:
-我有一个任务表,其中包含一个受让人列,一个创建列和一个已解决列 (创建和解决的都是时间戳)

+---------+----------+------------+------------+  
| task_id | assignee |  created   |  resolved  |  
+---------+----------+------------+------------+  
| tsk1    | him      | 2000-01-01 | 2018-01-03 |  
+---------+----------+------------+------------+

-我有一个更改日志表,其中包含task_id,一个from列,一个to列和一个date列,该记录记录每次更改受让人的情况

+---------+----------+------------+------------+  
| task_id | from     |  to        |  date      |  
+---------+----------+------------+------------+  
| tsk1    | me       | you        | 2017-04-06 |  
+---------+----------+------------+------------+  
| tsk1    | you      | him        | 2017-04-08 |  
+---------+----------+------------+------------+ 

我想选择一个表,该表显示间隔内从事任务的所有受让人的列表

+---------+----------+------------+------------+  
| task_id | assignee |  from      |  to        |  
+---------+----------+------------+------------+  
| tsk1    | me       | 2000-01-01 | 2017-04-06 |  
+---------+----------+------------+------------+  
| tsk1    | you      | 2017-04-06 | 2017-04-08 |  
+---------+----------+------------+------------+  
| tsk1    | him      | 2017-04-08 | 2018-01-03 |  
+---------+----------+------------+------------+  

我在first(/ last)行中遇到麻烦,其中from(/ to)应该设置为created(/ resolved),我不知道如何用来自两个不同表的数据创建列...
我尝试过按自己的方式选择它们,然后将所有行与union合并,但我认为这不是一个很好的解决方案...

3 个答案:

答案 0 :(得分:1)

嗯。 。 。这比看起来要复杂。想法是使用lead()获取下一个日期,但是您需要使用tasks表中的信息来“增强”数据:

select task_id, to, date as fromdate,
       coalesce(lead(date) over (partition by task_id order by date),
                max(resolved) over (partition by task_id)
               ) as todate
from ((select task_id, to, date, null::timestamp
       from log l
      ) union all
      (select distint on (t.task_id) t.task_id, l.from, t.created, t.resolved
       from task t join
            log l
            on t.task_id = l.task_id
       order by t.task_id, l.date
      )
     ) t;

答案 1 :(得分:0)

demo:db<>fiddle

SELECT 
    l.task_id, 
    assignee_from as assignee, 
    COALESCE(
         lag(assign_date) OVER (ORDER BY assign_date), 
         created
    ) as date_from,
    assign_date as date_to
FROM 
    log l 
JOIN
    task t
ON l.task_id = t.task_id

UNION ALL

SELECT * FROM (
    SELECT DISTINCT ON (l.task_id)
        l.task_id, assignee_to, assign_date, resolved
    FROM 
        log l 
    JOIN
        task t
    ON l.task_id = t.task_id
    ORDER BY l.task_id, assign_date DESC
) s

ORDER BY task_id, date_from

UNION包括两部分:日志部分,最后是任务表的最后一行。

第一部分使用LAG() window function获取当前行的前一个日期。由于"me"没有上一行,因此将产生一个NULL值。因此,可以通过从created表中获取task日期来捕捉到这一点。

第二部分是获取最后一行:在这里,我通过DISTINCTORDER BY assign_date DESC获取日志的最后一行。所以我知道最后一个assignee_to。其余部分与第一部分类似:从任务表获取resolved值。

答案 2 :(得分:0)

多亏了S-Man和Gordon Linoff的回答,我才能够提出以下解决方案:

SELECT t.task_id,
t.item_from AS assignee,
COALESCE(lag(t.changelog_created) OVER (
  PARTITION BY t.task_id ORDER BY t.changelog_created), 
  max(t.creationdate) OVER (PARTITION BY t.task_id)) AS fromdate,
t.changelog_created as todate
FROM ( SELECT ch.task_id,
        ch.item_from,
        ch.changelog_created,
        NULL::timestamp without time zone AS creationdate
       FROM changelog_generic_expanded_view ch
       WHERE ch.field::text = 'assignee'::text
    UNION ALL
    ( SELECT DISTINCT ON (t_1.id_task) t_1.id_task,
        t_1.assigneekey,
        t_1.resolutiondate,
        t_1.creationdate
       FROM task_jira t_1
      ORDER BY t_1.id_task)) t;

注意:这是最终版本,因此名称有所不同,但是思路保持不变。

这基本上与Gordon Linoff的代码相同,但是我以相反的方向浏览changelog。
我使用UNION ALL的第二部分来生成最后一个受让人,而不是第一个(这是为了处理根本没有变更日志的情况,生成最后一个受让人而不涉及变更日志的情况)