【问题标题】:Repeatedly JOIN data horizontally水平重复连接数据
【发布时间】:2013-07-28 03:57:06
【问题描述】:

我有两个如下所示的表:

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

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

我可以通过使用 sproc(见下文)为给定日期范围(例如一个月 2013-07-01 <= Transactions.DateTime < 2013-08-01)生成每个类别的总和来做到这一点。但是我不知道如何在数据库,所以我决定我可以重复运行 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

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

谢谢!

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案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 FIDDLE EXAMPLE

    【讨论】:

      【解决方案2】:

      在这种情况下,您最好使用表值函数。

      我无法验证语法,但类似这样:

      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

      【讨论】:

        猜你喜欢
        • 2020-11-04
        • 2019-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-01
        • 2020-05-27
        • 2016-07-19
        • 2020-04-30
        相关资源
        最近更新 更多