web-dev-qa-db-ja.com

SQLを使用した年初来の集計の構築

SQLのみを使用して毎月の集計を作成するのに助けが必要です。

次の表を想像してください。

TranID  DateCode    Account Value
   1    20140101        1   5
   2    20140106        1   -3
   3    20140207        1   6
   4    20140409        1   3
   5    20140103        2   3
   6    20140215        2   7
   7    20140519        2   6

さまざまな日に取引がある2つのアカウントがあります。 7月にいると仮定して、この結果が得られるコードを記述したいと思います。

MonthID     Account YTD
20140101        1   2
20140201        1   8
20140301        1   8
20140401        1   11
20140501        1   11
20140601        1   11
20140701        1   11
20140101        2   3
20140201        2   10
20140301        2   10
20140401        2   10
20140501        2   16
20140601        2   16
20140701        2   16

私は日付をMonthCodeに変換できるはずだと思っています

DATEADD(day, -DAY(DateCode) + 1, DateCode) AS MonthCode

テーブルをそれ自体に結合することでこれをどうにか解決できるはずだと思いますが、実際には数値が正しくありません。また、何とかしてトランザクションなしの月も取得する必要があります。

どんな助けも大歓迎です!

モックデータを生成するコード:

Create table #Tran(
TranID int identity(1,1),
DateCode Date,
AccountCode varchar(50),
Value int
);

insert into #Tran (DateCode, AccountCode, Value)
values ('20140101', '1', 5),
('20140106', '1', -3),
('20140201', '1', 6),
('20140401', '1', 3),
('20140101', '2', 3),
('20140201', '2', 7),
('20140501', '2', 6);
1
Taher

SQL Server 2012の場合、次のサンプルデータが与えられます。

CREATE TABLE #t(TranID INT, DateCode DATE, Account INT, Value INT);
CREATE CLUSTERED INDEX x ON #t(Account, DateCode);

INSERT #t VALUES(1,'20140101',1,5 ),(2,'20140106',1,-3),(3,'20140207',1,6 ),
(4,'20140409',1,3 ),(5,'20140103',2,3 ),(6,'20140215',2,7 ),(7,'20140519',2,6 );

私はこのクエリを使用します(最初の行をストアドプロシージャのパラメーターとして想像してください)。

DECLARE @year INT = 2014, @cutoff DATE = NULL; -- just state the year

-- and optionally an explicit cutoff date (leave NULL for today)
SET @cutoff = '20140731';

DECLARE @startdate DATE = DATEADD(YEAR, @year-1900, 0);

;WITH accounts(a) AS
(
  SELECT DISTINCT Account FROM #t 
    WHERE DateCode >= @startdate
    AND DateCode < DATEADD(YEAR, 1, @startdate)
),
months(m) AS 
(
  SELECT TOP (12) DATEADD(MONTH, ROW_NUMBER() OVER 
      (ORDER BY s.[object_id])-1, @startdate)
    FROM sys.all_objects AS s
),
s AS
(
  SELECT a.a, m.m, v = COALESCE(SUM(t.Value),0)
  FROM accounts AS a 
  CROSS APPLY months AS m
  LEFT OUTER JOIN #t AS t
    ON t.DateCode >= m.m
    AND t.DateCode < DATEADD(MONTH, 1, m.m)
    AND t.Account = a.a
  WHERE m.m < COALESCE(@cutoff, SYSDATETIME())
  GROUP BY a.a, m.m
)
SELECT 
  MonthID = m, 
  Account = a, 
  YTD = SUM(v) OVER(PARTITION BY a ORDER BY m ROWS UNBOUNDED PRECEDING) 
FROM s
ORDER BY a,m;

SQL Server 2012より古いバージョンを使用している場合は、ここで代替アプローチのいくつかを試してみるとよいでしょう。

2
Aaron Bertrand

最初に、MonthValue(20140101、20140201など)と呼ぶ、必要なすべての月を含むテーブルが必要になります。

クエリは次のようになります。

SELECT MonthValue.DateCode, #Tran.AccountID,
  (SELECT Sum(Value) FROM #Tran as sub
   WHERE sub.AccountID = #Tran.AccountID 
    AND sub.DateCode BETWEEN DATEADD(day, -DAY(MonthValue.DateCode) + 1, DateCode) AND MonthValue.DateCode) AS YTD
FROM MonthValue LEFT OUTER Join #Tran ON MonthValue.DateCode = #Tran.DateCode
GROUP BY MonthValue.DateCode, #Tran.AccountID

私はそれをテストしませんでした、しかしそれはあなたが少なくともあなたが必要とするものに近づくべきです。

0
Rono