【问题标题】:Best way to obtain total summary row of query result获取查询结果总汇总行的最佳方法
【发布时间】:2015-12-29 18:49:28
【问题描述】:

我正在执行一个得到几千行结果的查询,而客户需要一行显示某些数字列的总和。我已经通过使用 group by grouping 集合来实现这一点,但是这个函数最多支持 32 个不在聚合函数中的列。我的问题是我有将近 45 列需要返回,而由于聚合函数,我只有 10 列被排除在组之外。

原来的查询是这样的:

    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), ())

我尝试将查询一分为二,这样 group by 中的列数就不会达到可用的最大值。如果我分别执行每个查询,我会得到所需的结果,但如果我将它们联合起来,则会出现错误(无法将 nvarchar 转换为数字)。

结果是这样的:

    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), ())

另一种方法(如果可能)是通过在 SQL 中对集合进行分组来删除组并使用 C# 生成一行,因为查询的结果是由 IEnumerable 接收的,但我不知道 SUM 函数是否可用。

我们将不胜感激。

提前致谢。

【问题讨论】:

  • 您是在显示数千行吗,每行在任何地方都有 45 列?
  • 是的,这是主要问题。我必须显示每一列。
  • 您是否使用循环来显示此数据?如果是这样,请计算该循环内的必要总和并在最后显示它们。顺便说一句,尝试在 Web 浏览器中显示太多数据通常会以泪水告终,以防万一您正在尝试这样做。
  • 我在 MVC 视图中显示它,并带有一个使用 IEnumerable 的 grid.mvc 表。由于表格支持分页,因此显示不是问题。我们已经对其进行了测试,显示没有摘要行的数据没有问题。你建议我应该如何计算应用程序中的总和?
  • 我想我可能会考虑在新表中提前计算您的“总计”行,并检索两个结果集,一个用于实际数据,一个用于总计,存储在新的单独表格。

标签: c# sql asp.net-mvc tsql


【解决方案1】:

如果您尝试做的基本上是所有数据加上总行,请考虑以下方法。不要按包含所有非聚合列的分组集进行分组,而是按行 ID 分组(现有一个,在所有数据行中应该是唯一的,或者是人为的,使用 row_number() 函数创建)。还可以考虑在计算总计后加入辅助表。

示例如下。

设置示例数据:

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);

下面的查询以您尝试的方式返回所有数据加上总行:

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), ());

输出是:

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

将其与下一个查询进行比较,该查询按 单个 列对数据进行分组。辅助表@origs 也加入数据分组后。

;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;

输出是相同的

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

【讨论】:

    【解决方案2】:

    鉴于只有几千行,我会使用存储过程将结果不带总计到一个临时表或表值变量中,然后将结果作为该表的UNION ALL 加上一个大总计超过了它的顶部。

    【讨论】:

      猜你喜欢
      • 2021-12-08
      • 2023-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-28
      • 1970-01-01
      相关资源
      最近更新 更多