I am relatively new to SQL queries, and Stack Overflow has previously pointed me in the right direction, either by reading other peoples issues or answering my specific question. But this one I can not find anything that would resolve my issue.
I have two data tables which I have joined together to create a list of transactions which belong to a particular account. This part I have done and works (probably not the most efficient coding, but it is to the best of my knowledge). I can post the code if required. The results look like this, the Balance column is calculated in the SQL query and is not in any table:
This is great but I want to include an Opening Balance line at the start which would sum all records in this account before a specific date and the balance would include the opening amount. I would like it to look like this:
Adjusted Code I am using:
SELECT Result.TransID, Result.TransDate, Result.Reference, Result.Description, Result.Amount, SUM(Result.Amount) OVER(PARTITION BY Result.ledgerRef ORDER BY Result.TransID) AS 'Balance' FROM ( (SELECT -1 TransID, NULL AS 'TransDate', NULL AS 'Reference', OB.Description, SUM(OB.Amount) AS 'Amount', SUM(OB.Amount) AS 'Balance', OB.LedgerRef FROM ( (SELECT -1 AS 'ID', MAX(T.dtm_TransDate) AS 'TransDate', ' ' AS 'Reference', 'Opening Balance' AS 'Description', SUM(CASE WHEN LT.txt_LedgerTypeRef = 'REV' then -TD.dbl_TransDataAmount WHEN LT.txt_LedgerTypeRef = 'EXP' then TD.dbl_TransDataAmount WHEN LT.txt_LedgerTypeRef = 'ASS' then TD.dbl_TransDataAmount WHEN LT.txt_LedgerTypeRef = 'LIA' then -TD.dbl_TransDataAmount WHEN LT.txt_LedgerTypeRef = 'EQU' then -TD.dbl_TransDataAmount ELSE TD.dbl_TransDataAmount END) AS 'Amount', LT.txt_LedgerTypeRef AS 'LedgerRef' FROM dbo.tbl_TransData AS TD JOIN dbo.tbl_Trans AS T ON T.int_Trans_ID = TD.int_TransID JOIN dbo.tbl_TransType AS TT ON TT.int_TransType_ID = T.int_TransTypeID JOIN dbo.tbl_Account AS A ON A.int_Account_ID = TD.int_AccountID JOIN dbo.tbl_Ledger AS L ON L.int_Ledger_ID = A.int_LedgerID JOIN dbo.tbl_LedgerType AS LT ON LT.int_LedgerType_ID = L.int_LedgerTypeID WHERE T.int_BusinessID = 1 AND T.bit_Archive <> 1 AND T.bit_Disabled <> 1 AND T.bit_TransDelete <> 1 AND T.dtm_TransDate < '2019-01-01' AND TD.int_AccountID = 2167 GROUP BY LT.txt_LedgerTypeRef, TD.dbl_TransDataAmount ) UNION (SELECT -1 AS 'ID', MAX(T.dtm_TransDate) AS 'TransDate', ' ' AS 'Reference', 'Opening Balance' AS 'Description', SUM(CASE WHEN LT.txt_LedgerTypeRef = 'REV' THEN -T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'EXP' THEN T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'ASS' THEN T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'LIA' THEN -T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'EQU' THEN -T.dbl_TransAmount ELSE T.dbl_TransAmount END) AS 'Amount', LT.txt_LedgerTypeRef AS 'LedgerRef' FROM dbo.tbl_Trans AS T JOIN dbo.tbl_TransType AS TT ON TT.int_TransType_ID = T.int_TransTypeID JOIN dbo.tbl_Account AS A ON A.int_Account_ID = T.int_AccountIDBank JOIN dbo.tbl_Ledger AS L ON L.int_Ledger_ID = A.int_LedgerID JOIN dbo.tbl_LedgerType AS LT ON LT.int_LedgerType_ID = L.int_LedgerTypeID WHERE T.int_BusinessID = 1 AND T.bit_Archive <> 1 AND T.bit_Disabled <> 1 AND T.bit_TransDelete <> 1 AND T.dtm_TransDate < '2019-01-01' AND T.int_AccountIDBank = 2167 GROUP BY LT.txt_LedgerTypeRef, T.dbl_TransAmount ) ) AS OB GROUP BY OB.Description, OB.LedgerRef ) UNION (SELECT TR.TransID, TR.TransDate, TR.Reference, TR.Description, TR.Amount, SUM(TR.amount) OVER(PARTITION BY TR.ledgerRef ORDER BY TR.TransID) AS 'Balance', TR.LedgerRef FROM ( (SELECT T.int_Trans_ID AS 'TransID', T.dtm_TransDate AS 'TransDate', concat(TT.txt_TransTypeCode, T.dbl_TransRef) AS 'Reference', TD.txt_TransDataDescription AS 'Description', CASE WHEN LT.txt_LedgerTypeRef = 'REV' then -TD.dbl_TransDataAmount WHEN LT.txt_LedgerTypeRef = 'EXP' then TD.dbl_TransDataAmount WHEN LT.txt_LedgerTypeRef = 'ASS' then TD.dbl_TransDataAmount WHEN LT.txt_LedgerTypeRef = 'LIA' then -TD.dbl_TransDataAmount WHEN LT.txt_LedgerTypeRef = 'EQU' then -TD.dbl_TransDataAmount ELSE TD.dbl_TransDataAmount END AS 'Amount', LT.txt_LedgerTypeRef AS 'LedgerRef' FROM dbo.tbl_TransData AS TD JOIN dbo.tbl_Trans AS T ON T.int_Trans_ID = TD.int_TransID JOIN dbo.tbl_TransType AS TT ON TT.int_TransType_ID = T.int_TransTypeID JOIN dbo.tbl_Account AS A ON A.int_Account_ID = TD.int_AccountID JOIN dbo.tbl_Ledger AS L ON L.int_Ledger_ID = A.int_LedgerID JOIN dbo.tbl_LedgerType AS LT ON LT.int_LedgerType_ID = L.int_LedgerTypeID WHERE T.int_BusinessID = 1 AND T.bit_Archive <> 1 AND T.bit_Disabled <> 1 AND T.bit_TransDelete <> 1 AND T.dtm_TransDate >= '2019-01-01' AND TD.int_AccountID = 2167 ) UNION (SELECT T.int_Trans_ID AS 'TransID', T.dtm_TransDate AS 'TransDate', concat(TT.txt_TransTypeCode, T.dbl_TransRef) AS 'Reference', T.txt_TransDescription AS 'Description', CASE WHEN LT.txt_LedgerTypeRef = 'REV' THEN -T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'EXP' THEN T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'ASS' THEN T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'LIA' THEN -T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'EQU' THEN -T.dbl_TransAmount ELSE T.dbl_TransAmount END AS 'Amount', LT.txt_LedgerTypeRef AS 'LedgerRef' FROM dbo.tbl_Trans AS T JOIN dbo.tbl_TransType AS TT ON TT.int_TransType_ID = T.int_TransTypeID JOIN dbo.tbl_Account AS A ON A.int_Account_ID = T.int_AccountIDBank JOIN dbo.tbl_Ledger AS L ON L.int_Ledger_ID = A.int_LedgerID JOIN dbo.tbl_LedgerType AS LT ON LT.int_LedgerType_ID = L.int_LedgerTypeID WHERE T.int_BusinessID = 1 AND T.bit_Archive <> 1 AND T.bit_Disabled <> 1 AND T.bit_TransDelete <> 1 AND T.dtm_TransDate >= '2019-01-01' AND T.int_AccountIDBank = 2167 ) ) AS TR ) ) AS Result
This all seems to work fine, where I had to union the 2 tables for the opening balance and the transactions, so lots of unions there.
This is what the results look like:
Just one point, on the opening balance line, I would like the Amount to be blank, but if I leave it out of the opening balance query, the balance carried forward is wrong. It is on line 17 of the code. Not sure it can be done.
Once again any advise would be much appreciated.
Advertisement
Answer
Without having all your tables and going through a full setup and sample populating, I can offer the following…
Your INNER query is pre-grabbing all the transactions and details and union together into one set… of which you then outer query sum them.
I would add one more adjust the query something like (and again, just guidance vs full data prep and all).
select … original fields and sum(…)( over/order by) from ( InnerQuery1 UNION InnerQuery2 )
and change to
select … original fields and sum(…)( over/order by) from ( InnerQuery1 where TransDate > YourCutoffDate UNION InnerQuery2 where TransDate > YourCutoffDate UNION ( select -- place-holder field to match the union requirements -1 int_Trans_ID, MAX( ExistingDataDate ) AS 'TransDate', ' ' as 'Reference', 'Balance Forward' as 'Description', SUM( CASE WHEN LT.txt_LedgerTypeRef = 'REV' THEN -T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'EXP' THEN T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'ASS' THEN T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'LIA' THEN -T.dbl_TransAmount WHEN LT.txt_LedgerTypeRef = 'EQU' THEN -T.dbl_TransAmount ELSE T.dbl_TransAmount END ) AS 'Amount', LT.txt_LedgerTypeRef AS 'LedgerRef' from . . . where TransDate <= YourCutoffDate group by ?LedgerReg -- unsure per your data sources ) )
In this case, you can always run the new query for balance forward on its own merit to make sure that makes syntax and aggregation sense you INTEND to get. By using the WHERE clause to limit the top queries to only include those AFTER whatever cut-off date, those will be their own. This new query will pre-aggregate into a single row (per ledger) for all transactions PRIOR TO the cutoff leaving only 1 record (per ledger). Using the MAX() on the transaction date will make sure it floats to the top by date order and should be first thus starting your balance forward value.
Hope this make sense as the rest of the query you have is already working. Here, you are in essence just pre-querying all records ON or PRIOR TO the cutoff date and adding to the list. So build this query on its own first, THEN adjust your existing to include as additional union.
For your final removal of opening balance amount. You have a controlled value of the ID = -1. Use a case/when to remove. In your OUTERMOST query, change
Revision to clear opening balance amount line…
Result.Amount, SUM(Result.Amount) OVER(PARTITION BY Result.ledgerRef ORDER BY
to
case when int_trans_id < 0 then 0 else Result.Amount end Amount, SUM(Result.Amount) OVER(PARTITION BY Result.ledgerRef ORDER BY