按条件聚合列

时间:2018-05-07 13:22:57

标签: postgresql

我必须为主页撰写正常运行时间报告。在可供我使用的表格中,我有2列。第一个是主页的状态(0表示离线,1表示在线),第二个表示此状态的持续时间(秒)。示例表可能如下所示:

-------------------------
|  Status  |  Duration  |  
-------------------------
|  0       |  50        |
-------------------------
|  1       |  10        |
-------------------------
|  1       |  20        |
-------------------------
|  1       |  50        |
-------------------------
|  0       |  50        |
-------------------------
|  0       |  50        |
-------------------------
|  1       |  20        |
-------------------------

这在我的报告中看起来不太好,因为相同的stati应该聚合成一行而不是像这样显示为多行:

-------------------------
|  Status  |  Duration  |  
-------------------------
|  0       |  50        |
-------------------------
|  1       |  80        |
-------------------------
|  0       |  100       |
-------------------------
|  1       |  20        |
-------------------------

有没有办法用PostgreSQL实现这个目标?

2 个答案:

答案 0 :(得分:1)

正如我已经说过的那样,您需要一个id/datetime列来跟踪进度。 只有这样,您才能在此方案中使用LEAD/LAG函数或TABIBITOSAN方法。

SQL Fiddle

PostgreSQL 9.6架构设置

CREATE TABLE t
    (id INT,Status int, Duration int)
;

INSERT INTO t
    (id,Status, Duration)
VALUES
    (1,0, 50),
    (2,1, 10),
    (3,1, 20),
    (4,1, 50),
    (5,0, 50),
    (6,0, 50),
    (7,1, 20)
;

查询1

SELECT STATUS
    ,Sum(duration)
FROM (
    SELECT t.*
        ,row_number() OVER (
            ORDER BY id
            ) - row_number() OVER (
            PARTITION BY STATUS ORDER BY id
            ) AS seq
    FROM t
    ) s
GROUP BY STATUS
    ,seq
ORDER BY max(id)

<强> Results

| status | sum |
|--------|-----|
|      0 |  50 |
|      1 |  80 |
|      0 | 100 |
|      1 |  20 |

答案 1 :(得分:0)

这种聚合可以通过使用窗口函数和分组来实现:

select max(status) status, sum(duration) duration from (
          select status, duration, sum(case when status <> par then 1 else 0 end) over (order by id) wf from ( 
            select id, status, duration, lag(status, 1) over () par from test
          ) a order by id
      ) a group by wf order by wf

您只需在窗口功能中正确设置排序。

测试数据:

create table test (status int, duration int, id bigserial primary key);

insert into test (status, duration) values (0, 50);
insert into test (status, duration) values (1, 10);
insert into test (status, duration) values (1, 20);
insert into test (status, duration) values (1, 50);
insert into test (status, duration) values (0, 50);
insert into test (status, duration) values (0, 50);
insert into test (status, duration) values (1, 20);

输出就像你想要的那样。