2

我有两个看起来像这样的表:

Categories ( CategoryId, Type, Name )
Transactions ( TxnId, DateTime, Amount, CategoryId )

我想获得每个月每个类别SUM的所有交易。

我可以通过有一个 sproc(见下文)来做到这一点,它为给定日期范围(例如一个月)的每个类别生成总和2013-07-01 <= Transactions.DateTime < 2013-08-01。但是我不知道如何为数据库中的所有月份执行此操作,所以我决定我可以重复运行存储过程(给定不同的最小/最大日期)以获得不同月份的总和。

我想将结果合并到一个表中。

我的类别 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

....但这是无效的,那么解决这个问题的最佳方法是什么?

谢谢!

4

2 回答 2

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

请参阅SQL 小提琴示例

于 2013-07-28T04:37:48.490 回答
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

于 2013-07-28T04:10:36.217 回答