如何汇总计数组的数量

时间:2014-01-14 00:43:27

标签: sql sql-server group-by sql-server-2008-r2 rollup

ROLLUP允许在多个分组级别进行聚合,就像我UNIONed多个简单的SELECT语句一样。

但我希望能够聚合较低级别的分组结果,就像我使用嵌套的SELECT语句或依赖于彼此的CTE链一样。

例如,我希望能够从较低级别的分组中计算组数或计算较低级别或最小值的较低级别的总和的平均值,e.t.c。

更具体的例子:如果我有美国每次车祸的记录,我不仅要知道ROLLUP(州,县,市,邮编)各个级别的事故,还要计算人数(显然每个人可能涉及多起事故,因而涉及多个记录。)

用ROLLUP可以实现吗? 如果可能,那怎么样?

带结果的SQL示例:

if object_id('accident') is not null drop table accident
create table accident(
     id int identity(1,1)
    ,state varchar(50)
    ,city varchar(50)
    ,zip varchar(50)
    ,person varchar(50)
)

insert accident(state,city,zip,person)values
 ('NY','Manhattan',10001,'John')
,('NY','Manhattan',10001,'John')
,('NY','Manhattan',10001,'Barbara')

select
    state,city,zip,person
    ,accidents=count(1)
    -- the following line causes error: Windowed functions cannot be used in the context of another windowed function or aggregate.
    --,people=sum(case when row_number()over(partition by person order by (select 0))=1 then 1 else 0 end)
from accident
group by rollup(state,city,zip,person)

;with person as (select state,city,zip,person from accident group by state,city,zip,person)
    select
        state,city,zip
        ,people=count(1)
    from person
    group by rollup(state,city,zip)

结果:

state   city    zip person  accidents
NY  Manhattan   10001   Barbara 1
NY  Manhattan   10001   John    2
NY  Manhattan   10001   NULL    3
NY  Manhattan   NULL    NULL    3
NY  NULL    NULL    NULL    3
NULL    NULL    NULL    NULL    3


state   city    zip people
NY  Manhattan   10001   2
NY  Manhattan   NULL    2
NY  NULL    NULL    2
NULL    NULL    NULL    2

参见第一个结果,每个级别返回3个事故,第二个返回2个。 如果想在一个ROLLUP查询中同时获得3和2。 我的问题是窗口函数不能嵌套。

使用此查询可以实现我刚刚提出的问题:

;with person as (select state,city,zip,person,accidents=count(1) from accident group by state,city,zip,person)
        select
            state,city,zip
            ,accidents=sum(accidents)
            ,people=count(1)
        from person
        group by rollup(state,city,zip)

state   city    zip accidents   people
NY  Manhattan   10001   3   2
NY  Manhattan   NULL    3   2
NY  NULL    NULL    3   2
NULL    NULL    NULL    3   2

但这样做需要明确地为每个级别编写CTE。

我希望能够编写一个查询,无论分组级别如何,都可以访问较低级别的分组结果。

试过这个:

;with
    lvl as (
            select *
                    ,lvl = -1
                    ,accidents=1
                    ,people=1
                from accident
            union all
            select accident.*
                    ,lvl = grouping_id(accident.state,accident.city,accident.zip,accident.person)
                    ,accidents=sum(accidents)
                    ,people=count(1)
                from accident
                join lvl prev on prev.lvl = (grouping_id(accident.state,accident.city,accident.zip,accident.person)+1)/2-1
                group by rollup(accident.state,accident.city,accident.zip,accident.person)
        )
        select * from lvl

但是有错误:

Msg 1015, Level 15, State 1, ...
An aggregate cannot appear in an ON clause unless it is in a subquery contained in a HAVING clause or select list, and the column being aggregated is an outer reference.
Msg 467, Level 16, State 1, ...
GROUP BY, HAVING, or aggregate functions are not allowed in the recursive part of a recursive common table expression 'lvl'.

相关问题:recursive sql function with rollup logic?

0 个答案:

没有答案