传播单个列的层次结构值

时间:2016-10-25 20:59:34

标签: sql sql-server postgresql

我有这样的结构表,表示状态变化。

+-----------+----------+----------------+-----------------+-------+
| record_id | group_id | attribute type |  change date    | value |
+-----------+----------+----------------+-----------------+-------+
|         1 |        1 | status         | 4/16/2008 18:59 | s1    |
|         2 |        1 | details        | 4/16/2008 18:59 | d5    |
|         3 |        1 | details        | 8/7/2008 18:31  | d2    |
|         4 |        1 | details        | 2/5/2009 22:15  | d1    |
|         5 |        1 | status         | 4/3/2009 21:27  | s2    |
|         6 |        1 | details        | 4/3/2009 21:27  | d7    |
|         7 |        2 | status         | 4/3/2009 21:46  | s1    |
|         8 |        2 | details        | 4/3/2009 21:46  | d1    |
+-----------+----------+----------------+-----------------+-------+

我想在两列中查询状态更改和状态详细信息更改,按时间戳分组(实际上任何状态更改都会更改细节,因此只有详细信息更改时间戳可用于更轻松的分组)并且状态传播到相关细节,像这样:

+-----------+-----------------+--------+---------+
| object id |  change date    | status | details |
+-----------+-----------------+--------+---------+
|         1 | 4/16/2008 18:59 | s1     | d5      |
|         1 | 8/7/2008 18:31  | s1     | d2      |
|         1 | 2/5/2009 22:15  | s1     | d1      |
|         1 | 4/3/2009 21:27  | s2     | d3      |
|         2 | 4/3/2009 21:46  | s1     | d1      |
+-----------+-----------------+--------+---------+

这是我开始使用的,但它留给我的是NULLs

        SELECT history.record_id,
                history.group_id,
                history.changedate,
                status_chages.value AS status,
                history.value AS details
        FROM history
        LEFT JOIN (SELECT
             history.group_id,
             history.changedate,
             history.value
             FROM history
             WHERE history.attribute_type = 'status') status_chages
        ON status_chages.group_id = history.group_id AND
           status_chages.changedate = history.changedate
        WHERE history.attribute = 'details'

我首先想到的是用前一行数据填充NULL。

但有没有更好的方法来查询上面列出的结果?

1 个答案:

答案 0 :(得分:2)

查询提供了所需的布局:

select 
    group_id, 
    change_date, 
    max(case attr_type when 'status' then value else null end) as status,
    max(case attr_type when 'status' then null else value end) as detail
from history
group by 1, 2
order by 1, 2;

 group_id |     change_date     | status | detail 
----------+---------------------+--------+--------
        1 | 2008-04-16 18:59:00 | s1     | d5
        1 | 2008-08-07 18:31:00 |        | d2
        1 | 2009-02-05 22:15:00 |        | d1
        1 | 2009-04-03 21:27:00 | s2     | d7
        2 | 2009-04-03 21:46:00 | s1     | d1
(5 rows)

您可以通过以下方式填充以前值的空值:

select
    group_id, 
    change_date, 
    max(status) over (partition by group_id, part) status,
    detail
from (
    select *, count(status) over (partition by group_id order by change_date) part
    from (
        select 
            group_id, 
            change_date, 
            max(case attr_type when 'status' then value else null end) as status,
            max(case attr_type when 'status' then null else value end) as detail
        from history
        group by 1, 2
        ) s
    ) s
order by 1, 2;

 group_id |     change_date     | status | detail 
----------+---------------------+--------+--------
        1 | 2008-04-16 18:59:00 | s1     | d5
        1 | 2008-08-07 18:31:00 | s1     | d2
        1 | 2009-02-05 22:15:00 | s1     | d1
        1 | 2009-04-03 21:27:00 | s2     | d7
        2 | 2009-04-03 21:46:00 | s1     | d1
(5 rows)    

Test it in rextester.