用t-sql构建复杂的报告,每一行都有自己的where条件

时间:2015-08-05 20:47:17

标签: tsql optimization sql-server-2012

我正在用T-SQL构建一个复杂的报告。用户向我提供了报告来源的表格,并且有大约10万行。表包含描述性属性和数字列,如下所示:

分段product_group gmis lpt numeric_field1 numeric_field2 numeric_field3

报告大约有一千行,报告的定义逐行排列:

'第一行的名称' - 3,4,5和lpt = 3中的段的numeric_field1和gmis<>的总和50

'第二行' - 1,2,3和lpt中段的num2之和<> 5,gmis = 7

'第3行' - 你为product_id = 7

取num2 + num3

'第4行' - 第1行+第2行

所以我最终得到的t-sql查询对每一行都有单独的select,然后是union all:

'Row number 1' name, (select sum(num1) from source_table where segment in (3,4,5) and lpt=3 and gmis <> 50) value
union
'Row number 2'  , (select sum(num2) from source_table where segment in (1,2,3) and lpt<> 5 and gmis = 7) 
union
'Row number 3' , (select sum(num2 + num3) from source_table where product_id = 7) 

..... .... 等

我错过了一些更聪明的方法来做这种查询吗?因为报告很慢......

1 个答案:

答案 0 :(得分:0)

假设您始终从同一个基表中进行选择并始终在不进行分组的情况下进行聚合,以下内容应符合您的目的。

  1. 您应该在单个表上执行一组操作,而不是组合多个选择。获取where子句并将它们组合成一个select语句,作为一组when子句来计算用于聚合的基本值。这意味着您只需要阅读一次源表:

    Select
        Case When segment in (3,4,5) and lpt = 3 and gmis <> 50 Then num1 Else 0 End As row1,
        Case When segment in (1,2,3) and lpt<> 5 and gmis = 7 Then num1 Else 0 End As row2,
        Case When product_id = 7 then (num2+num3) Else 0 End As row3
    From
        source_table
    
  2. 将此作为表表达式使用,并从表表达式中执行聚合选择。在这个例子中,我使用了CTE(公用表表达式):

    ;With Column_Values
    (
        row1,
        row2,
        row3
    )
    As
        (
            Select
                Case When segment in (3,4,5) and lpt = 3 and gmis <> 50 Then num1 Else 0 End As row1,
                Case When segment in (1,2,3) and lpt<> 5 and gmis = 7 Then num1 Else 0 End As row2,
                Case When product_id = 7 then (num2+num3) Else 0 End As row3
            From
                source_table
        )
    Select
        name,
        value
    From
        (
            Select
                Sum(row1) As [Row number 1],
                Sum(row2) As [Row number 2],
                Sum(row3) As [Row number 3],
                Sum(row1) + Sum(row2) As [Row number 4]
            From
                Column_Values
        )
    
  3. 您现在将值作为一系列列。要将它们转换为行,请使用unpivot命令:

    ;With Column_Values
    (
        row1,
        row2,
        row3
    )
    As
        (
            Select
                Case When segment in (3,4,5) and lpt = 3 and gmis <> 50 Then num1 Else 0 End As row1,
                Case When segment in (1,2,3) and lpt<> 5 and gmis = 7 Then num1 Else 0 End As row2,
                Case When product_id = 7 then (num2+num3) Else 0 End As row3
            From
                source_table
        )
    Select
        name,
        value
    From
        (
            Select
                Sum(row1) As [Row number 1],
                Sum(row2) As [Row number 2],
                Sum(row3) As [Row number 3],
                Sum(row1 + row2) As [Row number 4]
            From
                Column_Values
        ) pvt
    Unpivot
        (
            value For name In
                (
                    [Row number 1],
                    [Row number 2],
                    [Row number 3],
                    [Row number 4]
                )       
        ) As upvt
    
  4. 如果您仍然遇到性能问题,您可以考虑以下选项,具体取决于您的要求:

    •如果您不需要报告实时数据,则可以预先计算这些值,将其存储在另一个表格中并从此表格中进行报告。

    •如果您拥有企业版并且不需要报告实时数据,则可以在源表上放置一个列存储索引 - 在SQL Server 2012中,这使得表只读,因此必须删除每次将新数据加载到源表中时重新创建。聚合大型表时,列存储索引可以提供巨大的性能提升。

    •如果需要报告实时数据,可以使用索引视图。在视图中聚合数据时,这可能会提高性能。