SQL - 一次根据多个实体的先前行值计算行值

时间:2016-09-26 22:56:25

标签: sql sql-server iterator

我有以下情况:我有一份属于许多投资的交易清单。交易记录包含投资标识符,日期和总金额,但不包括运行余额。

交易表:

+------------+------------+--------+
| Investment | Date       | Gross  |
+------------+------------+--------+
| A          | 2015-01-01 |   +200 |
| B          | 2015-06-30 |   +500 |
| C          | 2016-01-10 |   +300 |
| A          | 2016-08-15 |   +100 |
| A          | 2016-09-21 |   -300 |
+------------+------------+--------+

余额存储在一个单独的表中,并且始终是最新的:

余额表:

+------------+------------+
| Investment | Balance    |
+------------+------------+
| A          |          0 |
| B          |        500 |
| C          |        300 |
+------------+------------+

我想要做的是获得每笔交易的运行余额,一次性达到某一点的所有投资。

例如,如果我想显示2016年1月1日至2016年8月31日期间的投资A,B和C的交易,并且有余额,我会得到:

结果:

+------------+------------+--------+-------------+
| Investment | Date       | Gross  | End Balance |
+------------+------------+--------+-------------+
| C          | 2016-01-10 |    300 |         300 |
| A          | 2016-08-15 |    100 |         300 |
+------------+------------+--------+-------------+

我想在没有迭代器的情况下理想地执行此操作,因为我认为它效率低下。此外,理想的情况是使用余额表并从当前余额向后工作,因为当我通常只需要显示一些和最近的那些时,投资可能有很多交易。 / p>

非常感谢你的帮助。

2 个答案:

答案 0 :(得分:0)

使用CROSS APPLY获取运行余额

SELECT t.Investment, t.Date, t.Gross, b.Balance
FROM   Transaction t
       CROSS APPLY
       (
           SELECT balance = SUM(x.Gross)
           FROM   Transaction x
           WHERE  x.Invenstment = t.Investment
           AND    x.Date <= t.Date
       ) b
WHERE  t.Date >= '2016-01-01'
AND    t.Date <= '2016-08-31'

编辑:处理多个具有相同日期的trans

; with Trans as
(
    SELECT *, rn = row_number() over (partition by Investment order by Date)
    FROM   Transaction
)
SELECT t.Investment, t.Date, t.Gross, b.Balance
FROM   Trans t
       CROSS APPLY
       (
           SELECT balance = SUM(x.Gross)
           FROM   Trans x
           WHERE  x.Invenstment = t.Investment
           AND    x.rn <= t.rn
       ) b
WHERE  t.Date >= '2016-01-01'
AND    t.Date <= '2016-08-31'

答案 1 :(得分:0)

如果您使用的是SQL 2012或更高版本,请尝试使用以下查询。

   ;with cte_1
    AS (SELECT    Investment,Date
                 ,Gross
                 ,SUM(Gross) OVER(Partition by Investment ORDER BY Date
 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) EndBalance
                ,ROW_NUMBER()OVER(Partition By Investment Order By Date DESC)RNO
            FROM Transaction 
         WHERE Date between @starDate AND @endDate
         )

    SELECT     *
    FROM cte_1 A
    WHERE RNO =1