SSRS如何获取矩阵行组的第一个和最后一个值?

时间:2015-01-15 20:12:14

标签: matrix reporting-services ssrs-2012

我基本上将截图作为我的布局。

我的矩阵列是DCG1和DCG2。

在Matrix的最后,我有一个Total Group,它可以找到。但我想找到我的第一个和最后一个值之间的差异。我已尝试过ReportItems的所有内容!价值观。我无法让SSRS识别这些值。

所以基本上在下面的屏幕截图中。屏幕截图1是矩阵结构。我有一个名为Test1的列组,我想要测试1的第一个值和测试1的最后一个值,并将其放在红色框中。

在屏幕截图2中,您可以看到我想要比较的值。表分组的名称与列+组相同。所以dcs1group / dcs2group

enter image description here

enter image description here

好的,这是数据源的DDL和DML

http://pastebin.com/1ySN701D

已除去糊剂。为什么,不确定如此,它在下面。

IF EXISTS
      (SELECT [name]
         FROM tempdb.sys.tables
        WHERE [name] LIKE '%tmpHoldingTable%')
   BEGIN
      DROP TABLE #tmpHoldingTable;
   END;


CREATE TABLE #tmpHoldingTable
(
   dcs1    NVARCHAR (50),
   dcs2    NVARCHAR (50),
   Total   DECIMAL (10, 2),
   Test1   NVARCHAR (50)
)

INSERT INTO #tmpHoldingTable (dcs1,
                              dcs2,
                              Total,
                              Test1)
VALUES ('Contract',
        'Breach of Contract',
        500.00,
        '01/01/2013-12/31/2013'),
       ('Contract',
        'Breach of Contract',
        300.00,
        '01/01/2014-12/31/2014'),
       ('Employment',
        'Discrimination',
        500.00,
        '01/01/2013-12/31/2013'),
       ('Employment',
        'Discrimination',
        300.00,
        '01/01/2014-12/31/2014'),
       ('Employment',
        'Research',
        500.00,
        '01/01/2013-12/31/2013'),
       ('Employment',
        'Research',
        300.00,
        '01/01/2014-12/31/2014')

SELECT * FROM #tmpHoldingTable;

2 个答案:

答案 0 :(得分:7)

是的,这是可能的,但你可以看到它有点复杂。

为了使这个更通用的答案,我创建了自己的 DataSet ,简化了列但数据更多:

select grp = 1, val = 100, dt = cast('01-jan-2015' as date)
union all select grp = 1, val = 110, dt = cast('01-jan-2015' as date)
union all select grp = 1, val = 200, dt = cast('02-jan-2015' as date)
union all select grp = 1, val = 210, dt = cast('02-jan-2015' as date)
union all select grp = 1, val = 300, dt = cast('03-jan-2015' as date)
union all select grp = 1, val = 310, dt = cast('03-jan-2015' as date)
union all select grp = 1, val = 400, dt = cast('04-jan-2015' as date)
union all select grp = 1, val = 410, dt = cast('04-jan-2015' as date)
union all select grp = 1, val = 500, dt = cast('05-jan-2015' as date)
union all select grp = 1, val = 510, dt = cast('05-jan-2015' as date)
union all select grp = 2, val = 220, dt = cast('02-jan-2015' as date)
union all select grp = 2, val = 230, dt = cast('02-jan-2015' as date)
union all select grp = 2, val = 320, dt = cast('03-jan-2015' as date)
union all select grp = 2, val = 330, dt = cast('03-jan-2015' as date)
union all select grp = 2, val = 420, dt = cast('04-jan-2015' as date)
union all select grp = 2, val = 430, dt = cast('04-jan-2015' as date)

enter image description here

请注意,每个 grp / dt 组合都有两个值,{em> dt 的grp 1范围超过 dt grp 2

我基于此创建了一个简单的矩阵:

enter image description here

由于您使用的是SQL Server 2012,因此可以使用LookupSet函数获取每行组的第一个/最后一个值。

第一个行组TextBox中的表达式为:

=Code.SumLookup(
    LookupSet(
        First(Fields!dt.Value, "grp").ToString & Fields!grp.Value.ToString
        , Fields!dt.Value.ToString & Fields!grp.Value.ToString
        , Fields!val.Value
        , "DataSet1"
    )
)

根据我的示例数据,这给出了我所需的结果:

enter image description here

请注意,第二行grp行的范围比第一行窄,但其第一列/最后一列对每个组都是独立的,因此在每个grp内都是正确的。 这里有很多事情要发生。

汇总LookUpSet结果

的自定义代码

LookupSet表达式包含在Code.SumLookup自定义函数中:

Function SumLookup(ByVal items As Object()) As Decimal
  If items Is Nothing Then
    Return Nothing
  End If

  Dim suma As Decimal = New Decimal()
  suma = 0

  For Each item As Object In items
    suma += Convert.ToDecimal(item)
  Next

  Return suma
End Function

这取自this SO问题的回答。

这假设每个矩阵单元可以是多个值的总和,因此需要总结。 LookupSet返回一个值数组,由Code.SumLookup汇总。

LookupSet

的详细信息

接下来,LoopupSet表达式本身:

    LookupSet(
        First(Fields!dt.Value, "grp").ToString & Fields!grp.Value.ToString
        , Fields!dt.Value.ToString & Fields!grp.Value.ToString
        , Fields!val.Value
        , "DataSet1"
    )

LookupSet采用以下参数:

LookupSet(source_expression, destination_expression, result_expression, dataset)

在我们的表达式中,我们希望获取DataSet1中与当前dt范围内的第一个grp匹配的所有值。

对于source_expression我使用:

First(Fields!dt.Value, "grp").ToString & Fields!grp.Value.ToString

这将获取行范围中的第一个 dt "grp"是行组的名称),然后将其附加到当前的 grp 。在DataSet1中搜索时,这会创建一个匹配类似表达式的表达式。

即。 destination_expression

Fields!dt.Value.ToString & Fields!grp.Value.ToString

最后,我们指定我们希望Fields!val.Valueresult_expressionDataSet1dataset参数。

Fields!val.Value中所有匹配的DataSet1值都按LookupSet构建到数组中,然后由Code.SumLookup汇总。

更新上次值的表达式

Last TextBox的表达式几乎相同;只需将First更改为Last

=Code.SumLookup(
    LookupSet(
        Last(Fields!dt.Value, "grp").ToString & Fields!grp.Value.ToString
        , Fields!dt.Value.ToString & Fields!grp.Value.ToString
        , Fields!val.Value
        , "DataSet1"
    )
)

获得差异

最后,为了得到这些差异,只需在差异 TextBox中从另一个中减去一个表达式,或者甚至引用ReportItems值:

=ReportItems!Last.Value - ReportItems!First.Value

LastFirst是TextBox的名称。

<强>结论

显然,您需要根据具体情况进行更新,但您可以看到这可以完成。

您的报告中是否值得这样做?您可以看到涉及许多步骤,并且通常在生成DataSet时更容易解决。但是,如果这不是一个选项,希望这种LookupSet方法很有用。

答案 1 :(得分:1)

AFAIK这在单独的SSRS中是不可能的。相信我,我试过了。幸运的是,你有一个SQL数据源,所以我会在那里解决这个要求你有(几乎)无限的权力来塑造和操纵数据。

例如,我会用:

替换你的最终选择

; WITH CTE_Base AS ( SELECT * FROM #tmpHoldingTable ) , CTE_Test1 AS ( SELECT Test1 , ROW_NUMBER () OVER ( ORDER BY Test1 ) AS Column_Number_Test1 FROM CTE_Base GROUP BY Test1 ) SELECT CTE_Base.* , CTE_Test1.Column_Number_Test1 , CASE WHEN CTE_Test1.Column_Number_Test1 = 1 THEN Total WHEN CTE_Test1.Column_Number_Test1 = ( SELECT MAX ( Column_Number_Test1 ) FROM CTE_Test1 ) THEN 0 - Total ELSE 0 END AS [Difference] FROM CTE_Base INNER JOIN CTE_Test1 ON CTE_Base.Test1 = CTE_Test1.Test1

这会在[Difference]列中添加第1列的[Total]副本和最后一列的0 - [Total]副本。

SQL可能会更高效,但希望将其分解为CTE更容易理解。

然后在SSRS设计器中,您可以在[Test1]列组外添加[Difference]列,并将其汇总(默认值)。

顺便说一句,你的测试数据看起来有点简单 - 它只会生成2列,所有单元格都有值。但它很棒你发布了DDL&amp; DML - 它可以轻松扩展数据和代码并对其进行测试。