web-dev-qa-db-ja.com

SSRS行列行グループの最初と最後の値を取得する方法は?

基本的に、レイアウトとして以下のスクリーンショットがあります。

私の行列列はDCG1とDCG2です。

マトリックスの最後に、私はトータルグループを持っています。しかし、私はグループの最初と最後の値の違いを見つけたいと思っています。 ReportItemsからすべてを試しました!値に。 SSRSにこれらの値を認識させることができません。

したがって、基本的には以下のスクリーンショットにあります。スクリーンショット1はマトリックス構造です。 Test1という列グループがあり、Test1の最初の値とTest 1の最後の値が必要で、それを赤いボックスに配置します。

スクリーンショット2では、比較したい値を確認できます。テーブルのグループ化には、列+グループと同じ名前が付けられます。したがって、dcs1group/dcs2group

enter image description here

enter image description here

これがデータソースのDDLとDMLです

http://Pastebin.com/1ySN701D

Pastebinは削除されました。なぜかわからないので、ここでは以下に示します。

 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)、
合計DECIMAL(10、2)、
 Test1 NVARCHAR(50)
)
 
 INSERT INTO #tmpHoldingTable(dcs1、
 dcs2、
 Total、
 Test1)
 VALUES( 'Contract'、
 '違反契約 '、
 500.00、
' 01/01/2013-12/31/2013 ')、
('契約 '、
'契約違反 ' 、
 300.00、
 '01/01/2014-12/31/2014 ')、
(' Employment '、
' Discrimination '、
 500.00、
 '01/01/2013-12/31/2013 ')、
(' Empl oyment '、
'差別 '、
 300.00、
 '01/01/2014-12/31/2014')、
( '雇用'、
 '調査'、
 500.00、
 '01/01/2013-12/31/2013 ')、
('雇用 '、
 'Research'、
 300.00、
 '01/01/2014-12/31/2014 ')
 
 SELECT * FROM #tmpHoldingTable; 
8
user222427

はい、これは可能ですが、ご覧のとおり、少し複雑です。

これをより一般的な答えにするために、列を簡略化してデータを増やした独自の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の組み合わせには2つの値があり、grp 1dtgrp 2より。

これに基づいて簡単なマトリックスを作成しました。

enter image description here

SQL Server 2012を使用しているため、LookupSet関数を使用して、行グループごとの最初/最後の値を取得できます。

First行グループ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

2番目の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)

この式では、現在のdtスコープの最初のgrpに一致するすべての値をDataSet1から取得する必要があります。

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_expressionとして、DataSet1datasetパラメーターとして指定します。

Fields!val.Value内の一致するすべてのDataSet1値は、LookupSetによって配列に構築され、次にCode.SumLookupによって集約されます。

最後の値の式を更新します

LastTextBoxの式は実質的に同じです。 FirstLastに変更するだけです。

=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"
    )
)

違いを得る

最後に、これらの差を取得するには、DifferenceTextBoxで一方の式を他方から減算するか、ReportItems値を参照します。 :

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

ここで、LastFirstはTextBoxの名前です。

結論

明らかに、特定のケースに合わせて更新する必要がありますが、これが実行できることがわかります。

レポートでこれを行う価値はありますか?多くの手順が含まれていることがわかります。一般に、DataSetを生成するときに対処する方が簡単です。しかし、それが選択肢ではない場合は、このLookupSetアプローチが役立つことを願っています。

7
Ian Preston

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]列が追加され、最初の列に[Total]のコピーが追加され、最後の列に0- [Total]が追加されます。

SQLはおそらくより効率的にすることができますが、うまくいけば、SQLをCTEに分割する方が簡単です。

次に、SSRSデザイナで、[Test1]列グループの外に[Difference]列を追加し、合計することができます(デフォルト)。

ところで、テストデータは少し単純に見えます。2列しか生成されず、すべてのセルに値があります。しかし、DDLとDMLを投稿したことは素晴らしいことです。データとコードを拡張し、これをテストするのが簡単になりました。

1
Mike Honey