我有两个看起来像这样的表:
Categories ( CategoryId, Type, Name )
Transactions ( TxnId, DateTime, Amount, CategoryId )
我想每个月获得每个类别的所有交易的SUM
。
我可以通过设置一个sproc(见下文)来生成这个,它为每个类别生成给定日期范围的总和(例如一个月2013-07-01 <= Transactions.DateTime < 2013-08-01
。但是我不知道如何为所有月份做到这一点在数据库中,所以我决定我可以反复运行sproc(给定不同的最小/最大日期)来获得不同月份的总和。
我想将结果合并到一个表中。
我的类别sum sproc看起来像这样:
SELECT
Categories.Name,
Categories.Type,
Categories.CategoryId,
CategorySpendingForMonth.Amount
FROM
Categories
LEFT OUTER JOIN (
SELECT
CategoryId,
SUM(Amount) AS Amount
FROM
Txns
WHERE
[DateTime] >= @fromDate
AND
[DateTime] < @toDate
GROUP BY
CategoryId
) AS CategorySpendingForMonth ON Categories.CategoryId = CategorySpendingForMonth.CategoryId
ORDER BY
Categories.Type,
Categories.Name
我的结果如下:
Name Type CatId Amount
Car 0 9 -183.22
Electricity 0 12 -86.05
Insurance 0 17 NULL
Internet 0 14 -39.99
Phone 0 23 -50.04
Rent 0 19 -2284.80
Xoom 0 25 -604.99
但我希望它看起来像这样:
Name Type CatId June July Aug
Car 0 9 -183.22 -183.22 -183.22
Electricity 0 12 -86.05 -86.05 -86.05
Insurance 0 17 NULL -12.30 NULL
Internet 0 14 -39.99 -39.99 -39.99
Phone 0 23 -50.04 -50.04 -50.04
Rent 0 19 -2284.80 -2284.80 -2284.80
Xoom 0 25 -604.99 -604.99 -604.99
(并在额外的月份添加其他列)
所以我想我可以简单地为每个月添加数据来调用我的sproc,但我不知道如何将我现有的数据加入到这里(如果它是垂直的我会使用UNION ,但这是横向的。
这就是我的想法(无效的SQL):
SELECT
Name,
Type,
CategoryId,
Amount
FROM
EXEC CategoriesSummary( '2013-07-01', '2013-08-01' )
FOR i = 0 TO 12
LEFT OUTER JOIN CategoriesSummary( '2013-' + (7 + i) +'-01', '2013-' + (8 + 1) + '-01' )
NEXT
....但那是无效的,那么解决这个问题的最佳方法是什么?
谢谢!
答案 0 :(得分:1)
要获得更一般的解决方案,请在其他问题https://stackoverflow.com/a/13583258/1744834中查看我的答案。
对于不太通用的解决方案:),您可以使用PIVOT:
declare @Year int = 2013
;with CTE as
(
select C.Name, datepart(mm, T.DateTime) as M, sum(T.Amount) as Amount
from Txns as T
left outer join Categories as C on C.categoryId = T.categoryID
where
T.DateTime >= dateadd(yy, 2013 - datepart(yy, 0), 0) and
T.DateTime < dateadd(yy, 2013 - datepart(yy, 0) + 1, 0)
group by C.Name, datepart(mm, T.DateTime)
)
select
Name,
p.[1] as [January],
p.[2] as [February],
p.[3] as [March],
p.[4] as [April],
p.[5] as [May],
p.[6] as [June],
p.[7] as [July],
p.[8] as [August],
p.[9] as [September],
p.[10] as [October],
p.[11] as [November],
p.[12] as [December]
from CTE as C
pivot
(
sum(Amount)
for M in ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12])
) as p
答案 1 :(得分:0)
在这种情况下,你可能最好使用表值函数。
我无法验证语法,但是这样:
CREATE FUNCTION dbo.tvf(@fromDate DATETIME)
RETURNS @rows TABLE
(
val UNIQUEIDENTIFIER PRIMARY KEY
)
AS
BEGIN
INSERT INTO @rows
SELECT
valId AS val
FROM
Values
WHERE changed > @fromDate
ORDER BY
valid
RETURN
END
然后您可以像以下一样使用您的TVF:
SELECT * FROM dbo.tvf('1/1/2000')
TVF的文档在这里:http://msdn.microsoft.com/en-us/library/ms191165(v=SQL.105).aspx