From SQL to SPL: Calculate monthly account balance and fill in missing dates

There is a transaction table for the asset accounts in the MS SQL database, with dates that are not consecutive.

Name

Date

Debit

Credit

A

2021-01-01

10

0

A

2021-01-01

9

0

A

2021-02-01

11

0

A

2021-03-01

0

50

A

2021-04-01

30

0

B

2021-01-01

10

0

B

2022-02-01

0

12

B

2022-03-01

0

50

B

2024-04-01

3

0

Now we need to calculate the balance of each account for each month from January 2021 at the beginning of the period to April 2024 at the end of the period, and fill in the missing months.

Name

y

m

Blance

A

2021

1

-19

A

2021

2

-30

A

2021

3

20

A

2021

4

-10

A

2021

5

-10

A

2024

3

-10

A

2024

4

-10

B

2021

1

-10

B

2021

2

-10

B

2022

1

-10

B

2022

2

2

B

2022

3

52

B

2022

4

52

B

2024

3

52

B

2024

4

49

SQL Solution


WITH Accounts AS (
    SELECT DISTINCT Name FROM trans
),
Months AS (
    SELECT DATEADD(MONTH, n, '2021-01-01') AS MonthStart
    FROM (
        SELECT TOP (DATEDIFF(MONTH, '2021-01-01', '2024-04-01') + 1) 
        ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS n
        FROM master.dbo.spt_values
    ) AS Numbers
),
AccountMonths AS (
    SELECT a.Name, m.MonthStart
    FROM Accounts a
    CROSS JOIN Months m
),
Changes as (
    SELECT Name, DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0) as ym,
    sum(Credit - Debit) as change 
    FROM trans group by Name, DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)
),
fullChanges as (
    SELECT A.Name,A.MonthStart,c.change 
    FROM AccountMonths a left join Changes c 
    on a.Name=c.Name and a.MonthStart=c.ym
)
SELECT 
   Name,YEAR(MonthStart) AS Y,MONTH(MonthStart) AS M,
   SUM(change) OVER (PARTITION BY Name ORDER BY MonthStart) AS balance
   FROM fullChanges

SQL does not have a convenient method to generate a months sequence, so nested queries and window functions are required, and the code is very complex.

SPL provides functions for generating dates sequence, including consecutive months.


 A

1

=mssql.query("select Name, DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)as ym,sum(Credit - Debit) as change from trans group by Name, DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)”)

2

=periods@m(date("2021-01-01"),date("2024-04-01"),1)

3

=xjoin(A1.id(Name):Name; A2:ym)

4

=A3.join(Name:ym, A1:Name:ym,change)

5

=A4.new(Name,year(ym):y,month(ym):m,change+if(Name==Name[-1] , Balance[-1]):Balance)

A1 Query the database, group by account and date of the first day of each month, and calculate the monthly amount changes.

A2 Generate a continuous sequence consisting of the first day of each month. periods() generates a dates sequence, and @m represents the interval unit in month.

A3 Cross joint the account and date sequence.

A4 Left join the last cross-join result with A1.

A5 When the current account remains unchanged compared to the previous record, the current month's balance equals the change in the current month's amount plus the previous month's balance; When the account changes, the current month balance is reset to the current month amount change.

Question sourcehttps://stackoverflow.com/questions/78296238/aggregate-financial-transactions-into-monthly-balances