T-SQL 无循环迭代计算

T-SQL iterative calculation without loop

我有以下财务数据,我需要显示截至日期的余额。 我在下面的逻辑中使用了循环,但我想在没有循环或游标的情况下使用单个查询来实现同样的事情。对此的任何想法都会有所帮助。

 DROP TABLE IF EXISTS #Transact;
    CREATE TABLE #Transact
    (
        dt DATE,
        Transact VARCHAR(1),
        Amount INT,
        Balance INT
    )
    
    INSERT INTO #Transact
    (
        dt,
        Transact,
        Amount
    )
    SELECT *
    FROM
    (
        VALUES
            ('01-01-2022', 'C', 1000),
            ('02-01-2022', 'C', 1000),
            ('03-01-2022', 'D', 1000),
            ('04-01-2022', 'C', 2000),
            ('05-01-2022', 'C', 2000),
            ('06-01-2022', 'D', 2000),
            ('07-01-2022', 'D', 2000),
            ('08-01-2022', 'C', 3000),
            ('09-01-2022', 'C', 1500),
            ('10-01-2022', 'D', 1500),
            ('11-01-2022', 'D', 1500),
            ('12-01-2022', 'C', 1500)
    ) VTE (DT, Transact, Amount);
    
    declare @interval date = '01-01-2022',
            @balance int
    
    WHILE (@interval <= (select max(dt) FROM #Transact))
    BEGIN
        ;WITH CTE
         AS (SELECT *,
                    LAG(Balance) Over (Order by dt) AS PreBalance
             FROM #Transact
            )
        UPDATE CTE
        SET Balance = CASE
                          WHEN Transact = 'C' THEN
                              Amount + ISNULL(PreBalance, 0)
                          ELSE
                              ISNULL(PreBalance, 0) - Amount
                      END
        WHERE dt = @interval
    
        SET @interval = DATEADD(DAY, 1, @interval)
        SELECT @balance = Balance
        from #Transact
        where dt = @interval
    END
    
    SELECT * FROM #Transact;

我有大量这样的数据,我的要求是避免游标或循环进行此计算。

我认为这是一个 运行 总数,所以你需要一个窗口 SUM() 和一个 CASE 表达式:

SELECT 
   dt, Transact, Amount, 
   SUM(
      CASE 
         WHEN Transact = 'C' THEN Amount 
         WHEN Transact = 'D' THEN -Amount
         ELSE 0
      END) OVER (ORDER BY dt) AS Balance
FROM #Transact   

您是否尝试过像这样的简单查询:

SELECT
(
    SELECT SUM(Amount) FROM #Transact WHERE Transact = 'C' and dt <= @interval
)
-
(
    SELECT SUM(Amount) FROM #Transact WHERE Transact = 'D' and dt <= @interval
)
as Balance

基本上,您只需计算所有贷项并减去所有借项,直到日期为止。

或者,按照@Zhorov 的建议:

SELECT SUM
(
    CASE 
        WHEN Transact = 'C' THEN Amount 
        WHEN Transact = 'D' THEN -Amount
        ELSE 0
  END
) as Balance
FROM #Transact WHERE dt <= @interval