如何计算T-SQL中所有帐户的SUM余额?

时间:2013-05-11 18:47:37

标签: sql-server tsql sql-server-2012

我有这个表和数据

CREATE TABLE #transactions (
    [transactionId] [int] NOT NULL,
    [accountId] [int] NOT NULL,
    [dt] [datetime] NOT NULL,
    [balance] [smallmoney] NOT NULL,
 CONSTRAINT [PK_transactions_1] PRIMARY KEY CLUSTERED 
(   [transactionId] ASC)
) 

INSERT #transactions ([transactionId], [accountId], [dt], [balance]) VALUES 
(1, 1, CAST(0x0000A13900107AC0 AS DateTime), 123.0000),
(2, 1, CAST(0x0000A13900107AC0 AS DateTime), 192.0000),
(3, 1, CAST(0x0000A13A00107AC0 AS DateTime), 178.0000),
(4, 2, CAST(0x0000A13B00107AC0 AS DateTime), 78.0000),
(5, 2, CAST(0x0000A13D011D1860 AS DateTime), 99.0000),
(6, 2, CAST(0x0000A13F00000000 AS DateTime), 97.0000),
(7, 1, CAST(0x0000A13D0141E640 AS DateTime), 201.0000),
(8, 3, CAST(0x0000A1420094DD60 AS DateTime), 4000.0000),
(9, 3, CAST(0x0000A14300956A00 AS DateTime), 4100.0000),
(10, 3, CAST(0x0000A14700000000 AS DateTime), 4200.0000),
(11, 2, CAST(0x0000A14B00B84BB0 AS DateTime), 110.0000)

我需要两个查询。

  1. 对于每笔交易,我想在查询中返回每个帐户的最新余额,以及在该时间点每个帐户余额的余额的额外列。

  2. 与1相同,但按日期分组,没有时间部分。因此,每个帐户的每一天结束时(在任何帐户中都有交易)的最新帐户余额,但在1中一起进行SUMed。

  3. 上面的数据是我刚刚编写的示例数据,但我的真实表有数百行和10个帐户(可能会很快增加)。每个帐户都有一个唯一的accountId。看起来相当棘手的SQL。

    实施例

    对于1.我需要这样的结果:

    +---------------+-----------+-------------------------+---------+-------------+
    | transactionId | accountId |           dt            | balance | sumBalances |
    +---------------+-----------+-------------------------+---------+-------------+
    |             1 |         1 | 2013-01-01 01:00:00.000 |     123 |         123 |
    |             2 |         1 | 2013-01-01 01:00:00.000 |     192 |         192 |
    |             3 |         1 | 2013-01-02 01:00:00.000 |     178 |         178 |
    |             4 |         2 | 2013-01-03 01:00:00.000 |      78 |         256 |
    |             5 |         2 | 2013-01-05 17:18:00.000 |      99 |         277 |
    |             7 |         1 | 2013-01-05 19:32:00.000 |     201 |         300 |
    |             6 |         2 | 2013-01-07 00:00:00.000 |      97 |         298 |
    |             8 |         3 | 2013-01-10 09:02:00.000 |    4000 |        4298 |
    |             9 |         3 | 2013-01-11 09:04:00.000 |    4100 |        4398 |
    |            10 |         3 | 2013-01-15 00:00:00.000 |    4200 |        4498 |
    |            11 |         2 | 2013-01-19 11:11:00.000 |     110 |        4511 |
    +---------------+-----------+-------------------------+---------+-------------+
    

    因此,对于transactionId 8,我依次为每个帐户选择最新的balance,然后将它们相加。 AccountID 1:是201,AccountId 2是97而AccountId 3是4000.因此transactionId 8的结果将是201 + 97 + 4000 = 4298。该集必须按dt

    排序

    对于2.我需要这个

    +------------+-------------+
    |    date    | sumBalances |
    +------------+-------------+
    | 01/01/2013 |         192 |
    | 02/01/2013 |         178 |
    | 03/01/2013 |         256 |
    | 05/01/2013 |         300 |
    | 07/01/2013 |         298 |
    | 10/01/2013 |        4298 |
    | 11/01/2013 |        4398 |
    | 15/01/2013 |        4498 |
    | 19/01/2013 |        4511 |
    +------------+-------------+
    

    因此,截至2013年1月15日,每个账户的最新账户余额(1,2,3)为201,97,4200。因此该日期的结果将是201 + 97 + 4200 = 4498

2 个答案:

答案 0 :(得分:3)

这会提供您想要的第一个结果集(SQL Fiddle

WITH T
     AS (SELECT *,
                balance - 
                  isnull(lag(balance) OVER (PARTITION BY accountId 
                                             ORDER BY dt, transactionId), 0) AS B
         FROM   #transactions)
SELECT transactionId,
       accountId,
       dt,
       balance,
       SUM(B) OVER (ORDER BY dt, transactionId ROWS UNBOUNDED PRECEDING) AS sumBalances
FROM   T
ORDER  BY dt; 

它从之前的余额中减去帐户的当前余额以获得净差额,然后计算这些差异的累计总数。

这可以作为第二个结果的基础

WITH T1
 AS (SELECT *,
            balance - 
              isnull(lag(balance) OVER (PARTITION BY accountId 
                                         ORDER BY dt, transactionId), 0) AS B
     FROM   #transactions),
T2 AS (         
SELECT transactionId,
       accountId,
       dt,
       balance,
       ROW_NUMBER() OVER (PARTITION BY CAST(dt AS DATE) ORDER BY dt DESC, transactionId DESC) AS RN,
       SUM(B) OVER (ORDER BY dt, transactionId ROWS UNBOUNDED PRECEDING) AS sumBalances
FROM   T1)
SELECT CAST(dt AS DATE) AS [date], sumBalances
FROM T2
WHERE RN=1
ORDER  BY [date]; 

答案 1 :(得分:2)

第1部分

; WITH a AS (
    SELECT *, r = ROW_NUMBER()OVER(PARTITION BY accountId ORDER BY dt)
    FROM #transactions t
)
, b AS (
    SELECT t.*
    , transamount = t.balance - ISNULL(t0.balance,0)
    FROM a t
    LEFT JOIN a t0 ON t0.accountId = t.accountId AND t0.r + 1 = t.r
)
SELECT transactionId, accountId, dt, balance
, sumBalance = SUM(transamount)OVER(ORDER BY dt, transactionId)
FROM b
ORDER BY dt

第2部分

; WITH a AS (
    SELECT *, r = ROW_NUMBER()OVER(PARTITION BY accountId ORDER BY dt)
    FROM #transactions t
)
, b AS (
    SELECT t.*
    , transamount = t.balance - ISNULL(t0.balance,0)
    FROM a t
    LEFT JOIN a t0 ON t0.accountId = t.accountId AND t0.r + 1 = t.r
)
, c AS (
    SELECT transactionId, accountId, dt, balance
    , sumBalance = SUM(transamount)OVER(ORDER BY CAST(dt AS DATE))
    , r1 = ROW_NUMBER()OVER(PARTITION BY accountId, CAST(dt AS DATE) ORDER BY dt DESC)
    FROM b
)
SELECT dt = CAST(dt AS DATE)
, sumBalance
FROM c
WHERE r1 = 1
ORDER BY CAST(dt AS DATE)