0

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

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

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

更具体的例子:如果我有美国每起车祸的记录,我不仅想得到 ROLLUP(state,county,city,zip) 中每个级别的事故计数,还想得到人数(显然每个人可能是涉及多起事故并因此产生多份记录)。

是否可以使用 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'.

相关问题:具有汇总逻辑的递归 sql 函数?

4

0 回答 0