设置:SQL Server 2012,其中使用Report Builder 3.0在SSRS的折线图中使用数据
我有一张包含销售数据的表格,第一笔交易是在2010年10月10日。编写此表以定期更新销售信息,并将继续写入未来(当前日期为11/26/13,这就是样本表停在那里的原因)。
以下是我开始的原始数据示例:
StartDate Product PaidQty UnPaidQty
-------------------------------------------------------------
2012-10-10 Product A 100 150
2012-10-10 Product B 110 50
2012-10-10 Product C 10 100
2012-10-11 Product A 120 200
2012-10-11 Product D 140 230
2012-10-11 Product E 180 20
...
2013-05-01 Product H 120 60
2013-05-01 Product J 90 90
2013-05-01 Product K 120 160
...
2013-11-25 Product B 90 80
2013-11-25 Product F 190 180
2013-11-25 Product G 120 60
注意:每个日期可能没有值。例如,12/25/12没有一行。
我想要结束的应该是这样的:
StartDate DailyTotal AnnualTotal
--------------------------------------------
2012-10-10 520 520 <-- The Sum of 10/10/12 through 10/10/12
2012-10-11 890 1410 <-- The Sum of 10/10/12 through 10/11/12
...
2013-05-01 640 278,000 <-- The Sum of 10/10/12 through 05/01/13
...
2013-11-25 720 450,500 <-- The Sum of 11/26/12 through 11/25/13
获取每日总计列,结合PaidQty和UnPaidQty非常简单:
SELECT StartDate, SUM(PaidQty) + SUM(UnPaidQty) AS Total
FROM Table
GROUP BY StartDate
ORDER BY StartDate
但是,我需要最终提供的数据为我提供每日总计(付费+未付费)以及之前365天的总计。因此,因为在10/10/2012之前没有数据,所以运行总计将从2010年10月10日到2013年11月10日之间的总和相加,此时它将总计StartDate
值的总和 - 365天。有大量的产品清单,其中任何一种都可以在任何一天销售,但对于我的最终结果,我不关心产品。使用GROUP BY
子句可以使用此信息,以便为每个日期返回单行。
我只是没有抓住我需要做的事情才能为正在运行的年度总数添加额外的列。我尝试过使用OVER()
子句,例如:
SELECT StartDate, SUM(PaidQty) + SUM(UnPaidQty) AS Total, SUM(PaidQty) + SUM(UnPaidQty) OVER (ORDER BY StartDate) AS AnnualTotal
FROM Table
GROUP BY StartDate
ORDER BY StartDate
但是这会导致PaidQty和UnPaidQty需要在聚合函数或GROUP BY
子句中的错误。如果我将这些添加到GROUP BY
子句中,那么我最终会为每个日期重复多行,并且运行值不正确。
编辑:正如下面Aaron的回答所示,我最终得到了以下问题:
IF OBJECT_ID('tempdb..#x') IS NOT NULL DROP TABLE #x
CREATE TABLE #x
(
StartDate DATETIME,
PaidQty INT,
UnPaidQty INT
)
INSERT INTO #x
SELECT StartDate, SUM(PaidQty), SUM(UnPaidQty)
FROM MyTable
GROUP BY StartDate
SELECT Date, PaidQty+UnPaidQty AS DailyTotal,
SUM(PaidQty+UnPaidQty) OVER (Order By Date ROWS 364 PRECEDING) AS AnnualTotal
FROM CalendarDates
LEFT JOIN #x ON Date = StartDate
WHERE Date BETWEEN '2012-10-10' AND GetDate()
ORDER BY Date
我在我的数据库中创建了一个名为CalendarDates的表,它只包含从2010年1月1日到12月31日的所有日期的列表。这用于为没有完成销售的任何日期填写NULL。
答案 0 :(得分:3)
DECLARE @x TABLE(StartDate DATE, Product VARCHAR(30), PaidQty INT, UnPaidQty INT);
INSERT @x VALUES
('2012-10-10','Product A',100,150),
('2012-10-10','Product B',110,50 ),
('2012-10-10','Product C',10 ,100),
('2012-10-11','Product A',120,200),
('2012-10-11','Product D',140,230),
('2012-10-11','Product E',180,20 ),
('2012-10-12','Product B',90 ,80 ),
('2012-10-12','Product F',190,180),
('2012-10-12','Product G',120,60 );
;WITH x AS
(
SELECT StartDate, pq = SUM(PaidQty), uq = SUM(UnPaidQty)
FROM @x GROUP BY StartDate
)
SELECT StartDate, pq, uq,
SUM(pq+uq) OVER (ORDER BY StartDate ROWS 365 PRECEDING)
FROM x;
现在,假设每个日期都有一行。如果没有,您可能希望生成一组日期并将其用作左连接中的锚点。否则,之前的365行将代表超过365天。要做到这一点:
DECLARE @minDate DATE, @maxDate DATE, @delta INT;
SELECT @maxDate = MAX(StartDate), @minDate = MIN(StartDate) FROM @x;
SET @delta = DATEDIFF(DAY, @minDate, @maxDate);
IF @delta > 364
SELECT @minDate = DATEADD(DAY, -364, @maxDate), @delta = 364;
;WITH n(n) AS
(
SELECT TOP (@delta+1) ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_columns
),
d(d) AS (SELECT DATEADD(DAY, n-1, @minDate) FROM n),
x AS
(
SELECT StartDate = d.d, pq = SUM(PaidQty), uq = SUM(UnPaidQty)
FROM d LEFT OUTER JOIN @x AS x
ON d.d = x.StartDate GROUP BY d.d
)
SELECT StartDate, pq, uq,
SUM(pq+uq) OVER (ORDER BY StartDate ROWS 365 PRECEDING)
FROM x
ORDER BY StartDate;