2012-06-26 12 views
16

希望の階段ステップの出力と一致するMS SQL 2012クエリを作成する助けが必要です。行は1つの日付範囲(勘定提出日月)でデータを要約し、列は別の日付範囲(納付日付月)で要約します。SQL Stairstepクエリのヘルプが必要

表1 アカウントは、

CREATE TABLE [dbo].[Accounts](
    [AccountID] [nchar](10) NOT NULL, 
    [SubmissionDate] [date] NOT NULL, 
    [Amount] [money] NOT NULL, 
CONSTRAINT [PK_Accounts] PRIMARY KEY CLUSTERED (AccountID ASC)) 

INSERT INTO [dbo].[Accounts] VALUES ('1000', '2012-01-01', 1999.00) 
INSERT INTO [dbo].[Accounts] VALUES ('1001', '2012-01-02', 100.00) 
INSERT INTO [dbo].[Accounts] VALUES ('1002', '2012-02-05', 350.00) 
INSERT INTO [dbo].[Accounts] VALUES ('1003', '2012-03-01', 625.00) 
INSERT INTO [dbo].[Accounts] VALUES ('1004', '2012-03-10', 50.00) 
INSERT INTO [dbo].[Accounts] VALUES ('1005', '2012-03-10', 10.00) 

表2:トランストラックの支払いが行わ

CREATE TABLE [dbo].[Trans](
    [TranID] [int] IDENTITY(1,1) NOT NULL, 
    [AccountID] [nchar](10) NOT NULL, 
    [TranDate] [date] NOT NULL, 
    [TranAmount] [money] NOT NULL, 
CONSTRAINT [PK_Trans] PRIMARY KEY CLUSTERED (TranID ASC)) 

INSERT INTO [dbo].[Trans] VALUES (1000, '2012-01-15', 300.00) 
INSERT INTO [dbo].[Trans] VALUES (1000, '2012-02-15', 300.00) 
INSERT INTO [dbo].[Trans] VALUES (1000, '2012-03-15', 300.00) 
INSERT INTO [dbo].[Trans] VALUES (1002, '2012-02-20', 325.00) 
INSERT INTO [dbo].[Trans] VALUES (1002, '2012-04-20', 25.00) 
INSERT INTO [dbo].[Trans] VALUES (1003, '2012-03-24', 625.00) 
INSERT INTO [dbo].[Trans] VALUES (1004, '2012-03-28', 31.00) 
INSERT INTO [dbo].[Trans] VALUES (1004, '2012-04-12', 5.00) 
INSERT INTO [dbo].[Trans] VALUES (1005, '2012-04-08', 7.00) 
INSERT INTO [dbo].[Trans] VALUES (1005, '2012-04-28', 3.00) 

はここで所望の出力は、最初の2つのカラムは、月ごとにグループ化をAccount.Amount合計

        *Total Payments in Each Month* 
SubmissionYearMonth TotalAmount | 2012-01 2012-02 2012-03 2012-04 
-------------------------------------------------------------------- 
2012-01    2099.00  | 300.00 300.00 300.00  0.00 
2012-02    350.00  |   325.00  0.00 25.00 
2012-03    685.00  |     656.00 15.00 

どのように見えるかです。

最後の4つの列は、現在の行の指定された月に配置されたアカウントのTran.TranAmountを合計します。

私が働いていたクエリは近づいてきました。私はちょうど遅れを持っていません。

Select SubmissionYearMonth, 
     TotalAmount, 
     pt.[0] AS MonthOld0, 
     pt.[1] AS MonthOld1, 
     pt.[2] AS MonthOld2, 
     pt.[3] AS MonthOld3, 
     pt.[4] AS MonthOld4, 
     pt.[5] AS MonthOld5, 
     pt.[6] AS MonthOld6, 
     pt.[7] AS MonthOld7, 
     pt.[8] AS MonthOld8, 
     pt.[9] AS MonthOld9, 
     pt.[10] AS MonthOld10, 
     pt.[11] AS MonthOld11, 
     pt.[12] AS MonthOld12, 
     pt.[13] AS MonthOld13 

From (
     SELECT Convert(Char(4),Year(SubmissionDate)) + '-' + Right('00' + Convert(VarChar(2), DatePart(Month, SubmissionDate)),2) AS SubmissionYearMonth, 
     SUM(Amount) AS TotalAmount 
     FROM Accounts 
     GROUP BY Convert(Char(4),Year(SubmissionDate)) + '-' + Right('00' + Convert(VarChar(2), DatePart(Month, SubmissionDate)),2) 
    ) 
AS AccountSummary 
OUTER APPLY 
(
SELECT * 
FROM (
     SELECT CASE WHEN DATEDIFF(Month, SubmissionDate, TranDate) < 13 
        THEN DATEDIFF(Month, SubmissionDate, TranDate) 
        ELSE 13 
       END AS PaymentMonthAge, 
       TranAmount 
     FROM Trans INNER JOIN Accounts ON Trans.AccountID = Accounts.AccountID 
     Where Convert(Char(4),Year(TranDate)) + '-' + Right('00' + Convert(VarChar(2), DatePart(Month, TranDate)),2) 
      = AccountSummary.SubmissionYearMonth 
     ) as TransTemp 
     PIVOT (SUM(TranAmount) 
       FOR PaymentMonthAge IN ([0], 
             [1], 
             [2], 
             [3], 
             [4], 
             [5], 
             [6], 
             [7], 
             [8], 
             [9], 
             [10], 
             [11], 
             [12], 
             [13])) as TransPivot 
) as pt 

それは次のような出力を生成です:列日付ヘッダのよう

SubmissionYearMonth TotalAmount MonthOld0 MonthOld1 MonthOld2 MonthOld3 ... 
2012-01    2099.00  300.00 NULL  NULL  NULL  ... 
2012-02    350.00  325.00 300.00 NULL  NULL  ... 
2012-03    685.00  656.00 NULL  300.00 NULL  ... 

は、ここで私はこれまでで働いていたクエリです。私は最良の選択肢がここにあるのか分かりません。追加の列を追加して、結果のレポートで使用できる計算値を作成することができました。

SQLフィドル:どのような援助のためのhttp://www.sqlfiddle.com/#!6/272e5/1/0

感謝。

+9

**サンプルデータとクエリを含む**優れた**ジョブ。これはすべての質問をどのように書くべきかです。 – mellamokb

+3

@mellamokb:[SQLFiddle](http://sqlfiddle.com)へのリンクとそれは完璧だろう:) –

+2

@juergend:確かに。 OPのクエリは次のとおりです。http://www.sqlfiddle.com/#!3/56223/1 – mellamokb

答えて

1

Thomas、私は私が使用して終了し、次の解決のためのインスピレーションとしてあなたの応答を使用していました。

まず、SubmissionDate、TranDateクロス結合スケルトンの日付行列を作成します。これは後でAccountSummaryとTranSummaryデータに結合するために使用します。

結果のクエリ出力は、TranDate月ごとの列でフォーマットされません。むしろ、SQL Server Reporting Servicesマトリックスで出力を使用し、TranSummaryMonthNum列に基づいて列グループを使用して、目的の書式付き出力を取得しています。

SQL Fiddle version

; 
WITH 
    --Generate a list of Dates, from the first SubmissionDate, through today. 
    --Note: Requires the use of: 'OPTION (MAXRECURSION 0)' to generate a list with more than 100 dates. 
    CTE_AutoDates AS 
    (Select Min(SubmissionDate) as FiscalDate 
     From Accounts 
     UNION ALL 
     SELECT DATEADD(Day, 1, FiscalDate) 
     FROM CTE_AutoDates 
     WHERE DATEADD(Day, 1, FiscalDate) <= GetDate() 
    ), 

    FiscalDates As 
    (SELECT FiscalDate, 
      DATEFROMPARTS(Year(FiscalDate), Month(FiscalDate), 1) as FiscalMonthStartDate 
     FROM CTE_AutoDates 
     --Optionaly filter Fiscal Dates by the last known Math.Max(SubmissionDate, TranDate) 
     Where FiscalDate <= (Select Max(MaxDate) 
          From (Select Max(SubmissionDate) as MaxDate From Accounts 
           Union All 
           Select Max(TranDate) as MaxDate From Trans 
           ) as MaxDates 
         ) 
    ), 

    FiscalMonths as 
    (SELECT Distinct FiscalMonthStartDate 
     FROM FiscalDates 
    ), 

    --Matrix to store the reporting date groupings for the Account submission and payment periods. 
    SubmissionAndTranMonths AS 
    (Select AM.FiscalMonthStartDate as SubmissionMonthStartDate, 
      TM.FiscalMonthStartDate as TransMonthStartDate, 
      DateDiff(Month, (Select Min(FiscalMonthStartDate) From FiscalMonths), TM.FiscalMonthStartDate) as TranSummaryMonthNum 
     From FiscalMonths AS AM 
      Join FiscalMonths AS TM 
      ON TM.FiscalMonthStartDate >= AM.FiscalMonthStartDate 
    ), 

    AccountData as 
    (Select A.AccountID, 
      A.Amount, 
      FD.FiscalMonthStartDate as SubmissionMonthStartDate 
     From Accounts as A 
      Inner Join FiscalDates as FD 
      ON A.SubmissionDate = FD.FiscalDate 
    ), 


    TranData as 
    (Select T.AccountID, 
      T.TranAmount, 
      AD.SubmissionMonthStartDate, 
      FD.FiscalMonthStartDate as TranMonthStartDate 
     From Trans as T 
      Inner Join AccountData as AD 
      ON T.AccountID = AD.AccountID 
      Inner Join FiscalDates AS FD 
      ON T.TranDate = FD.FiscalDate 
    ), 

    AccountSummaryByMonth As 
    (Select ASM.FiscalMonthStartDate, 
      Sum(AD.Amount) as TotalSubmissionAmount 
     From FiscalMonths as ASM 
      Inner Join AccountData as AD 
      ON ASM.FiscalMonthStartDate = AD.SubmissionMonthStartDate 
     Group By 
      ASM.FiscalMonthStartDate 
    ), 

    TranSummaryByMonth As 
    (Select STM.SubmissionMonthStartDate, 
      STM.TransMonthStartDate, 
      STM.TranSummaryMonthNum, 
      Sum(TD.TranAmount) as TotalTranAmount 
     From SubmissionAndTranMonths as STM 
      Inner Join TranData as TD 
      ON STM.SubmissionMonthStartDate = TD.SubmissionMonthStartDate 
       AND STM.TransMonthStartDate = TD.TranMonthStartDate 
     Group By 
      STM.SubmissionMonthStartDate, 
      STM.TransMonthStartDate, 
      STM.TranSummaryMonthNum 
    ) 

--#Inspect 1 
--Select * From SubmissionAndTranMonths 
--OPTION (MAXRECURSION 0) 

--#Inspect 1 Results 
--SubmissionMonthStartDate TransMonthStartDate TranSummaryMonthNum 
--2012-01-01    2012-01-01   0 
--2012-01-01    2012-02-01   1 
--2012-01-01    2012-03-01   2 
--2012-01-01    2012-04-01   3 
--2012-02-01    2012-02-01   1 
--2012-02-01    2012-03-01   2 
--2012-02-01    2012-04-01   3 
--2012-03-01    2012-03-01   2 
--2012-03-01    2012-04-01   3 
--2012-04-01    2012-04-01   3 

--#Inspect 2 
--Select * From AccountSummaryByMonth 
--OPTION (MAXRECURSION 0) 

--#Inspect 2 Results 
--FiscalMonthStartDate TotalSubmissionAmount 
--2012-01-01   2099.00 
--2012-02-01   350.00 
--2012-03-01   685.00 

--#Inspect 3 
--Select * From TranSummaryByMonth 
--OPTION (MAXRECURSION 0) 

--#Inspect 3 Results 
--SubmissionMonthStartDate TransMonthStartDate TranSummaryMonthNum TotalTranAmount 
--2012-01-01    2012-01-01   0     300.00 
--2012-01-01    2012-02-01   1     300.00 
--2012-01-01    2012-03-01   2     300.00 
--2012-02-01    2012-02-01   1     325.00 
--2012-02-01    2012-04-01   3     25.00 
--2012-03-01    2012-03-01   2     656.00 
--2012-03-01    2012-04-01   3     15.00 

Select STM.SubmissionMonthStartDate, 
     ASM.TotalSubmissionAmount, 
     STM.TransMonthStartDate, 
     STM.TranSummaryMonthNum, 
     TSM.TotalTranAmount 
From SubmissionAndTranMonths as STM 
    Inner Join AccountSummaryByMonth as ASM 
     ON STM.SubmissionMonthStartDate = ASM.FiscalMonthStartDate 
    Left Join TranSummaryByMonth AS TSM 
     ON STM.SubmissionMonthStartDate = TSM.SubmissionMonthStartDate 
      AND STM.TransMonthStartDate = TSM.TransMonthStartDate 
Order By STM.SubmissionMonthStartDate, STM.TranSummaryMonthNum 
OPTION (MAXRECURSION 0) 

--#Results 
--SubmissionMonthStartDate TotalSubmissionAmount TransMonthStartDate TranSummaryMonthNum TotalTranAmount 
--2012-01-01    2099.00    2012-01-01   0     300.00 
--2012-01-01    2099.00    2012-02-01   1     300.00 
--2012-01-01    2099.00    2012-03-01   2     300.00 
--2012-01-01    2099.00    2012-04-01   3     NULL 
--2012-02-01    350.00    2012-02-01   1     325.00 
--2012-02-01    350.00    2012-03-01   2     NULL 
--2012-02-01    350.00    2012-04-01   3     25.00 
--2012-03-01    685.00    2012-03-01   2     656.00 
--2012-03-01    685.00    2012-04-01   3     15.00 
+3

親愛なるネイサンさん、誰かがあなたの質問に実質的に手伝ってくれたなら、私の意見では、自分の答えを選択して選択するのではなく、その人の答えを選択する必要があります。 – ErikE

1

次のクエリは、あなたが望むものを返すものです。あなたはto操作を別々に行う必要があります。私はちょうど一緒に結果を結合する:

select a.yyyymm, a.Amount, 
     t201201, t201202, t201203, t201204 
from (select LEFT(convert(varchar(255), a.submissiondate, 121), 7) as yyyymm, 
       SUM(a.Amount) as amount 
     from Accounts a 
     group by LEFT(convert(varchar(255), a.submissiondate, 121), 7) 
    ) a left outer join 
     (select LEFT(convert(varchar(255), a.submissiondate, 121), 7) as yyyymm, 
       sum(case when trans_yyyymm = '2012-01' then tranamount end) as t201201, 
       sum(case when trans_yyyymm = '2012-02' then tranamount end) as t201202, 
       sum(case when trans_yyyymm = '2012-03' then tranamount end) as t201203, 
       sum(case when trans_yyyymm = '2012-04' then tranamount end) as t201204 
     from Accounts a join 
      (select t.*, LEFT(convert(varchar(255), t.trandate, 121), 7) as trans_yyyymm 
      from trans t 
      ) t 
      on a.accountid = t.accountid 
     group by LEFT(convert(varchar(255), a.submissiondate, 121), 7) 
    ) t 
     on a.yyyymm = t.yyyymm 
order by 1 

あなたは2つのセルに0.00があるNULLを取得しています。

+0

日付範囲のエンドポイントは照会時に認識されません。クエリが実行されるたびに、固定された、または潜在的に可変の支払月要約列とともに、既知のすべてのアカウント提出月の行の一覧が作成されます。 いくつか余分なヌルは大したことではありません。 – Nathan

5

SQL Server 2012を使用しているため、[書式]機能を使用して日付をきれいにすることができます。文字列でグループ化する必要はありません。代わりに、可能な限り、適切なデータ型を使用し、フォーマットまたは変換のみを使用して表示するか、中間層が表示を処理するようにするのが便利です。

この解決策では、私は任意の最も早いTransDateを想定し、その月の最初の日から抽出します。しかし、その式を希望の開始日の静的な値で簡単に置き換えることができます。この解決策はそれと今後12ヶ月を取ることになります。

With SubmissionMonths As 
    (
    Select DateAdd(d, -Day(A.SubmissionDate) + 1, A.SubmissionDate) As SubmissionMonth 
    , A.Amount 
    From dbo.Accounts As A 
) 
    , TranMonths As 
    (
    Select DateAdd(d, -Day(Min(T.TranDate)) + 1, Min(T.TranDate)) As TranMonth 
     , 1 As MonthNum 
    From dbo.Accounts As A 
    Join dbo.Trans As T 
     On T.AccountId = A.AccountId 
    Join SubmissionMonths As M 
     On A.SubmissionDate >= M.SubmissionMonth 
     And A.SubmissionDate < DateAdd(m,1,SubmissionMonth) 
    Union All 
    Select DateAdd(m, 1, TranMonth), MonthNum + 1 
    From TranMonths 
    Where MonthNum < 12 
) 
    , TotalBySubmissionMonth As 
    (
    Select M.SubmissionMonth, Sum(M.Amount) As Total 
    From SubmissionMonths As M 
    Group By M.SubmissionMonth 
) 
Select Format(SMT.SubmissionMonth,'yyyy-MM') As SubmissionMonth, SMT.Total 
    , Sum(Case When TM.MonthNum = 1 Then T.TranAmount End) As Month1 
    , Sum(Case When TM.MonthNum = 2 Then T.TranAmount End) As Month2 
    , Sum(Case When TM.MonthNum = 3 Then T.TranAmount End) As Month3 
    , Sum(Case When TM.MonthNum = 4 Then T.TranAmount End) As Month4 
    , Sum(Case When TM.MonthNum = 5 Then T.TranAmount End) As Month5 
    , Sum(Case When TM.MonthNum = 6 Then T.TranAmount End) As Month6 
    , Sum(Case When TM.MonthNum = 7 Then T.TranAmount End) As Month7 
    , Sum(Case When TM.MonthNum = 8 Then T.TranAmount End) As Month8 
    , Sum(Case When TM.MonthNum = 9 Then T.TranAmount End) As Month9 
    , Sum(Case When TM.MonthNum = 10 Then T.TranAmount End) As Month10 
    , Sum(Case When TM.MonthNum = 11 Then T.TranAmount End) As Month11 
    , Sum(Case When TM.MonthNum = 12 Then T.TranAmount End) As Month12 
From TotalBySubmissionMonth As SMT 
    Join dbo.Accounts As A 
    On A.SubmissionDate >= SMT.SubmissionMonth 
     And A.SubmissionDate < DateAdd(m,1,SMT.SubmissionMonth) 
    Join dbo.Trans As T 
    On T.AccountId = A.AccountId 
    Join TranMonths As TM 
    On T.TranDate >= TM.TranMonth 
     And T.TranDate < DateAdd(m,1,TM.TranMonth) 
Group By SMT.SubmissionMonth, SMT.Total 

SQL Fiddle version

+0

これは非常に有望です。私はそれをちょっと試して、この実装を使用できるかどうかを見ていきます。ありがとう。 – Nathan

+0

+1良い答えです。また、解答を得るには彼の道具であったため、OPはあなたの答えを選択したはずであるはずです。 – ErikE

1

次のクエリでは、正確にyour final query in your own answerの結果を複製しますが、CPU(またはそれ以上)、1/30よりもかかりません、プラスずっと簡単です。

時間があったとすれば、さらに改善が見られると確信しています...私の腸は、Accountsテーブルを何度も叩く必要はないかもしれません。しかし、いずれにしても、それは大きな改善であり、非常に大きな結果セットであっても非常にうまくいくはずです。

the SqlFiddle for itを参照してください。

WITH L0 AS (SELECT 1 N UNION ALL SELECT 1), 
L1 AS (SELECT 1 N FROM L0, L0 B), 
L2 AS (SELECT 1 N FROM L1, L1 B), 
L3 AS (SELECT 1 N FROM L2, L2 B), 
L4 AS (SELECT 1 N FROM L3, L2 B), 
Nums AS (SELECT N = Row_Number() OVER (ORDER BY (SELECT 1)) FROM L4), 
Anchor AS (
    SELECT MinDate = DateAdd(month, DateDiff(month, '20000101', Min(SubmissionDate)), '20000101') 
    FROM dbo.Accounts 
), 
MNums AS (
    SELECT N 
    FROM Nums 
    WHERE 
     N <= DateDiff(month, 
     (SELECT MinDate FROM Anchor), 
     (SELECT Max(TranDate) FROM dbo.Trans) 
    ) + 1 
), 
A AS (
    SELECT 
     AM.AccountMo, 
     Amount = Sum(A.Amount) 
    FROM 
     dbo.Accounts A 
     CROSS APPLY (
     SELECT DateAdd(month, DateDiff(month, '20000101', A.SubmissionDate), '20000101') 
    ) AM (AccountMo) 
    GROUP BY 
     AM.AccountMo 
), T AS (
    SELECT 
     AM.AccountMo, 
     TM.TranMo, 
     TotalTranAmount = Sum(T.TranAmount) 
    FROM 
     dbo.Accounts A 
     CROSS APPLY (
     SELECT DateAdd(month, DateDiff(month, '20000101', A.SubmissionDate), '20000101') 
    ) AM (AccountMo) 
     INNER JOIN dbo.Trans T 
     ON A.AccountID = T.AccountID 
     CROSS APPLY (
     SELECT DateAdd(month, DateDiff(month, '20000101', T.TranDate), '20000101') 
    ) TM (TranMo) 
    GROUP BY 
     AM.AccountMo, 
     TM.TranMo 
) 
SELECT 
    SubmissionStartMonth = A.AccountMo, 
    TotalSubmissionAmount = A.Amount, 
    M.TransMonth, 
    TransMonthNum = N.N - 1, 
    T.TotalTranAmount 
FROM 
    A 
    INNER JOIN MNums N 
     ON N.N >= DateDiff(month, (SELECT MinDate FROM Anchor), A.AccountMo) + 1 
    CROSS APPLY (
     SELECT TransMonth = DateAdd(month, N.N - 1, (SELECT MinDate FROM Anchor)) 
    ) M 
    LEFT JOIN T 
     ON A.AccountMo = T.AccountMo 
     AND M.TransMonth = T.TranMo 
ORDER BY 
    A.AccountMo, 
    M.TransMonth; 
関連する問題