带有未分组列的SQL组

时间:2013-11-05 18:46:47

标签: sql postgresql group-by

我有一个具有以下结构的日志表:

CREATE TABLE mytable (
    oid        integer(10),
    department  integer(10),
    cid         integer(10),
    status      integer(1) comment 'statuses: 1-open, 2-accept, 3-done',
    recordtime  datetime
);

此表存储有关状态分配的一些数据。 oid - 组织,cid - card id。 当组织更新卡(设置新状态)在此表中插入行

时,组织会向部门发出警告

我尝试从该表中选择统计数据,例如:按部门或按组织(oid)选择最大/最小接受时间,最大/最小完成时间和平均接受/完成时间。

here is sql fiddle of the example table and my query

问题是如何在按部门分组时选择列中的cid,oid和oid以及按部门分组时cid。换句话说:我想知道组织(oid)和卡ID(cid),例如,当我选择分组行时,最大接受时间

我需要这些列用于多个连接

UPD:
感谢 Roman Pekar ,他的回答让我走上了正确的道路。我使用他的第二个查询来编写我的最终查询。

首先:按部门分别选择平均接受/完成时间,最大/最小接受/完成时间,然后选择oidcid以及每个部门的最长接受时间

with cte as (
    select
        oid, cid,
        max(case when status=1 then recorddatetime end) as open,
        max(case when status=2 then recorddatetime end) as accept,
        max(case when status=3 then recorddatetime end) as done
    from 
        mytable
    group by oid, cid
    having 
        max(case when status=1 then recorddatetime end) is not null and max(case when status=2 then recorddatetime end) is not null
        and max(case when status=3 then recorddatetime end) is not null
    order by oid, cid
)
select distinct on(department)
    department, oid, cid,
    ceil(extract(epoch from avg(cte.accept - cte.open) over (partition by department))) as avg_accept_time,
    ceil(extract(epoch from avg(done - open) over (partition by department))) as avg_done_time,
    ceil(extract(epoch from max(accept - open) over (partition by department))) as max_accept_time,
    ceil(extract(epoch from max(done - open) over (partition by department))) as max_done_time,
    ceil(extract(epoch from min(accept - open) over (partition by department))) as min_accept_time,
    ceil(extract(epoch from min(done - open) over (partition by department))) as min_done_time
from cte cte
order by department, max_accept_time desc

第二:与第一个类似,但为组织选择所有这些值(oid

with cte as (
        select
            oid, cid,
            max(case when status=1 then recorddatetime end) as open,
            max(case when status=2 then recorddatetime end) as accept,
            max(case when status=3 then recorddatetime end) as done
        from 
            mytable
        group by oid, cid
        having 
            max(case when status=1 then recorddatetime end) is not null and max(case when status=2 then recorddatetime end) is not null
            and max(case when status=3 then recorddatetime end) is not null
        order by oid, cid
    )
    select distinct on(department, oid)
        department, oid, cid,
        ceil(extract(epoch from avg(cte.accept - cte.open) over (partition by department, oid))) as avg_accept_time,
        ceil(extract(epoch from avg(done - open) over (partition by department, oid))) as avg_done_time,
        ceil(extract(epoch from max(accept - open) over (partition by department, oid))) as max_accept_time,
        ceil(extract(epoch from max(done - open) over (partition by department, oid))) as max_done_time,
        ceil(extract(epoch from min(accept - open) over (partition by department, oid))) as min_accept_time,
        ceil(extract(epoch from min(done - open) over (partition by department, oid))) as min_done_time
    from cte cte
    order by department, oid, max_accept_time desc

1 个答案:

答案 0 :(得分:2)

不知道你要对你的查询做什么,但它确实过于复杂。您可以使用窗口函数和没有连接来简化第一次查询:

with cte as (
    select
        oid, department, cid,
        max(case when status=1 then recordtime end) as open,
        max(case when status=2 then recordtime end) as accept,
        max(case when status=3 then recordtime end) as done
    from mytable
    group by oid, department, cid
)
select
    department, oid,
    extract(epoch from avg(accept - open)) as a_time,
    extract(epoch from avg(done - open)) as d_time,
    extract(epoch from max(accept - open)) as max_a_time,
    extract(epoch from max(done - open)) as max_d_time
from cte
group by department, oid
order by department, oid;

<强> sql fiddle demo

如果您希望从cid获得max_time,则可以使用distinct on语法:

with cte as (
    select
        oid, department, cid,
        max(case when status=1 then recordtime end) as open,
        max(case when status=2 then recordtime end) as accept,
        max(case when status=3 then recordtime end) as done
    from mytable
    group by oid, department, cid
)
select distinct on (department, oid)
    department, oid, cid,
    extract(epoch from accept - open) as a_time
from cte
order by department, oid, accept - open desc;

或使用排名函数row_number():

with cte as (
    select
        oid, department, cid,
        max(case when status=1 then recordtime end) as open,
        max(case when status=2 then recordtime end) as accept,
        max(case when status=3 then recordtime end) as done
    from mytable
    group by oid, department, cid
), cte2 as (
    select
        department, oid, cid,
        accept, open,
        row_number() over(
              partition by department, oid
              order by accept - open desc
        ) as rn
    from cte
)
select
    department, oid, cid,
    extract(epoch from accept - open) as a_time
from cte2
where rn = 1
order by department, oid

sql fiddle demo