简体   繁体   中英

Best way to obtain total summary row of query result

I'm executing a query that gets a couple thousands rows as result, and the customer needs a row showing the sum totals of certain numeric columns. I've achieved this by using group by grouping sets, but this function supports up to 32 columns that are not in aggregate functions. My problem is that I have nearly 45 columns that I have to return, being only 10 that I leave out of the group by because of aggregate functions.

Original query was something like this:

    select
    o.Name, 
    ci.Id,
    ci.OriginId,
    ci.Varchar1,
    ci.Varchar2,
    ci.Varchar3,
    ci.Varchar4,
    ci.Varchar5,
    ci.Varchar6,
    ci.Varchar7,
    ci.Varchar8,
    ci.Varchar9,
    ci.Varchar10,
    ci.Varchar11,
    ci.Varchar12,
    ci.Varchar13,
    ci.Varchar14,
    ci.Varchar15,
    ci.Varchar16,
    ci.Varchar17,
    ci.Varchar18,
    ci.Varchar19,
    ci.Varchar20,       
    sum(ci.Decimal1) as Decimal1,
    sum(ci.Decimal1) as Decimal2,
    sum(ci.Decimal1) as Decimal3,
    sum(ci.Decimal1) as Decimal4,
    sum(ci.Decimal1) as Decimal5,
    sum(ci.Decimal1) as Decimal6,
    sum(ci.Decimal1) as Decimal7,
    sum(ci.Decimal1) as Decimal8,
    sum(ci.Decimal1) as Decimal9,
    sum(ci.Decimal1) as Decimal10,
    ci.Date1,
    ci.Date2,
    ci.Date3,
    ci.Date4,
    ci.Date5,
    ci.Date6,
    ci.Date7,
    ci.Date8,
    ci.Date9,
    ci.Date10

from 
    Items ci
    inner join Origins o 
    on ci.OriginId = o.Id 

group by grouping sets((
    o.Name,
    ci.Id,
    ci.OriginId,
    ci.Varchar1,
    ci.Varchar2,
    ci.Varchar3,
    ci.Varchar4,
    ci.Varchar5,
    ci.Varchar6,
    ci.Varchar7,
    ci.Varchar8,
    ci.Varchar9,
    ci.Varchar10,
    ci.Varchar11,
    ci.Varchar12,
    ci.Varchar13,
    ci.Varchar14,
    ci.Varchar15,
    ci.Varchar16,
    ci.Varchar17,
    ci.Varchar18,
    ci.Varchar19,
    ci.Varchar20,
    ci.Date1,
    ci.Date2,
    ci.Date3,
    ci.Date4,
    ci.Date5,
    ci.Date6,
    ci.Date7,
    ci.Date8,
    ci.Date9,
    ci.Date10), ())

I've tried to split the query in two, so that the amount of columns in the group by doesn't reach the maximum available. If I execute each query separated I get the desired results, but if I union them I have an error (can't convert nvarchar to numeric).

The result was something like this:

    select      
    o.name
    ci.Id,
    ci.OriginId,
    sum(ci.Decimal1) as Decimal1,
    sum(ci.Decimal1) as Decimal2,
    sum(ci.Decimal1) as Decimal3,
    sum(ci.Decimal1) as Decimal4,
    sum(ci.Decimal1) as Decimal5,
    sum(ci.Decimal1) as Decimal6,
    sum(ci.Decimal1) as Decimal7,
    sum(ci.Decimal1) as Decimal8,
    sum(ci.Decimal1) as Decimal9,
    sum(ci.Decimal1) as Decimal10,
    ci.Date1,
    ci.Date2,
    ci.Date3,
    ci.Date4,
    ci.Date5,
    ci.Date6,
    ci.Date7,
    ci.Date8,
    ci.Date9,
    ci.Date10

from 
    Items ci
    inner join Origins o 
    on ci.OriginId = o.Id 


group by grouping sets((
    o.Name,
    ci.Id,
    ci.OriginId,        
    ci.Date1,
    ci.Date2,
    ci.Date3,
    ci.Date4,
    ci.Date5,
    ci.Date6,
    ci.Date7,
    ci.Date8,
    ci.Date9,
    ci.Date10), ())

union

select  
    o.Name,
    ci.Id,
    ci.OriginId,
    ci.Varchar1,
    ci.Varchar2,
    ci.Varchar3,
    ci.Varchar4,
    ci.Varchar5,
    ci.Varchar6,
    ci.Varchar7,
    ci.Varchar8,
    ci.Varchar9,
    ci.Varchar10,
    ci.Varchar11,
    ci.Varchar12,
    ci.Varchar13,
    ci.Varchar14,
    ci.Varchar15,
    ci.Varchar16,
    ci.Varchar17,
    ci.Varchar18,
    ci.Varchar19,
    ci.Varchar20

from 
    Items ci
    inner join Origins o 
    on ci.OriginId = o.Id 

group by grouping sets((
    o.name,
    ci.Id,
    ci.OriginId,

    ci.Varchar1,
    ci.Varchar2,
    ci.Varchar3,
    ci.Varchar4,
    ci.Varchar5,
    ci.Varchar6,
    ci.Varchar7,
    ci.Varchar8,
    ci.Varchar9,
    ci.Varchar10,
    ci.Varchar11,
    ci.Varchar12,
    ci.Varchar13,
    ci.Varchar14,
    ci.Varchar15,
    ci.Varchar16,
    ci.Varchar17,
    ci.Varchar18,
    ci.Varchar19,
    ci.Varchar20), ())

Another way (if possible), would be to drop the group by grouping sets in SQL and generate a row with C#, since the result of the query is recieved by a IEnumerable, but I don't know if a SUM function is available.

Any advice will be appreciated.

Thanks in advance.

If what you are trying to do is basically all data plus total row, consider the following approach. Do not group by grouping set that include all non-aggregated columns, instead group by row ID (existing one, which should be unique within all data rows, or artificial, created with row_number() function). Also consider joining auxiliary tables after total is calculated.

The example follows.

Setup sample data:

declare @origs table (id int, name varchar(20));
insert into @origs values (1, 'orig1'), (2, 'orig2');

declare @items table (
    id int, orig_id int,
    column1 varchar(20), column2 varchar(20),
    value1 float, value2 float);

insert into @items values
(1, 1, 'c1.1', 'c2.1', 100, 10)
,(2, 1, 'c1.2', 'c2.2', 200, 20)
,(3, 2, 'c1.3', 'c2.3', 300, 30);

The query below returns all data plus total row the way you are trying to do it:

select i.id, o.name as orig, i.column1, i.column2, sum(i.value1) val1, sum(i.value2) val2
from @items i
    join @origs o on o.id = i.orig_id
group by grouping sets ((i.id, o.name, i.column1, i.column2), ());

The output is:

id    orig  column1  column2  val1  val2
----- ----- -------- -------- ----- -----
1     orig1 c1.1     c2.1     100   10
2     orig1 c1.2     c2.2     200   20
3     orig2 c1.3     c2.3     300   30
NULL  NULL  NULL     NULL     600   60

Compare it to the next query, that groups data by a single column. Also auxiliary table @origs is joined after data is grouped.

;with items as (
    select
        case grouping(id) when 0 then max(id) else NULL end id,
        case grouping(id) when 0 then max(orig_id) else NULL end orig_id,
        case grouping(id) when 0 then max(column1) else NULL end column1,
        case grouping(id) when 0 then max(column2) else NULL end column2,
        val1 = sum(value1),
        val2 = sum(value2)
    from @items
    group by rollup (id)
)
select i.id, o.name as orig, i.column1, i.column2, i.val1, i.val2
from items i
    left join @origs o on o.id = i.orig_id;

Output is the same :

id    orig  column1  column2  val1  val2
----- ----- -------- -------- ----- -----
1     orig1 c1.1     c2.1     100   10
2     orig1 c1.2     c2.2     200   20
3     orig2 c1.3     c2.3     300   30
NULL  NULL  NULL     NULL     600   60

仅给出几千行,我将使用存储过程将没有总计的结果存储到临时表或表值变量中,然后将结果作为该表的UNION ALL加上顶部的总计返回它的。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM