Search code examples
sql-server-2005t-sqlgroup-byrollup

group by clause with rollup


I'm trying to use group by with rollup clause within sql server 2005 but I'm having some problem.

This is a simple dump

create table group_roll (
id int identity,
id_name int,
fname varchar(50),
surname varchar(50),
qty int
)

go
insert into group_roll (id_name,fname,surname,qty) values (1,'john','smith',10)
insert into group_roll (id_name,fname,surname,qty) values (1,'john','smith',30)
insert into group_roll (id_name,fname,surname,qty) values (2,'frank','white',5)
insert into group_roll (id_name,fname,surname,qty) values (1,'john','smith',8)
insert into group_roll (id_name,fname,surname,qty) values (2,'frank','white',10)
insert into group_roll (id_name,fname,surname,qty) values (3,'rick','black',10)
go

If I run this simple query

select id_name,fname,surname,sum(qty) as tot
from group_roll
group by id_name,fname,surname

I get

1   john    smith   48
2   frank   white   15
3   rick    black   10

I'd like to have

1   john    smith   48
2   frank   white   15
3   rick    black   10
Total                73

This is what I've tried to reach my goal

select 
case when grouping(id_name) = 1 then 'My total' else cast(id_name as char) end as Name_id ,
fname,surname,sum(qty) as tot
from group_roll
group by id_name,fname,surname
with rollup
order by case when id_name is null then 1 else 0 end, tot desc

but my result is

1                               john    smith   48
1                               john    NULL    48
1                               NULL    NULL    48
2                               frank   white   15
2                               frank   NULL    15
2                               NULL    NULL    15
3                               rick    black   10
3                               rick    NULL    10
3                               NULL    NULL    10
My total                         NULL   NULL   73

Where is my mistake?

EDIT. I could solve my problem making

select * from (
select cast(id_name as char) as id_name,fname,surname,sum(qty) as tot
from group_roll
group by id_name,fname,surname 
union
select 'Total',null,null,sum(qty) from group_roll ) as t
order by case when id_name = 'Total' then 1 else 0 end,tot desc

but I'd like to understand if rollup can solve my problem.


Solution

  • You cannot do it within the statement itself, however you can filter the ROLLUP set excluding the intermediate rollups, i.e. where any one but not all rows are being grouped:

    select
        case when grouping(id_name) = 1 then 'My total' else cast(id_name as char) end as Name_id,
        fname,
        surname,
        sum(qty) as tot
    from group_roll
    group by id_name, fname, surname
    with rollup
    having grouping(id_name) + grouping(fname) + grouping(surname) in (0 , 3)
    

    Or similar to your solution but referencing the original query;

    ;with T as (
        select cast(id_name as varchar(128)) as id_name,fname,surname,sum(qty) as tot
        from group_roll
        group by id_name,fname,surname
    ) select * from T union all select 'Total:',null,null, SUM(tot) from T
    

    FWIW SQL 2008 allows;

    select
        case when grouping(id_name) = 1 then 'My total' else cast(id_name as char) end as Name_id,
        fname,
        surname,
        sum(qty) as tot
    from group_roll
    group by grouping sets((id_name, fname, surname), ())