How to update running balance in one shot? - sql

I have a temp table, let's call it #invoices, defined as
create table (id int identity(1, 1), billed money, credited money, balance money)
i have the following data in it
Billed Credited
140.00
20.00
60.00
20.00
-20.00
I would like to update the balance column with the running balance. so that the Balance column is updated properly. Balance is basically, Billed - Credited, but has to take into the account the previous row.
So in my example, the Balance will be so:
Billed Credited Balance
140.00 140.00
20.00 160.00
60.00 100.00
20.00 80.00
-20.00 -100.00
Is there a way to do this without looping through the rows and keeping the running balance? Basically I am looking to update the Balance column in a set-based way.

There are set-based ways to calculate running totals in SQL Server, however in the current versions of SQL Server a cursor-based solution is often quicker.
Adam Machanic wrote a great article on it here.

The answer is triggers. I use them, and it works beautifully. I don't have exactly your setup (it's slightly strange, if I may say), but in general, they are the correct approach here. You will need to be mindful of ordering, but other than that, it should be fine.

Related

SQL where function used with Over Partition

I am calculation a range of figures, one of the calculated columns are a weighted average calculation based on "Accountlink" by "DTstamp".
The problem is that I need the final result (per accountlink) to show in a new column - each Accountlink's final result per accountlink - to be used in a new calculation - as per example below:
Accountlink WA_Calc WA_Calc_Final
1 20.00 30.00
1 40.00 30.00
1 30.00 30.00
2 15.00 20.00
2 35.00 20.00
2 28.00 20.00
on the image is an extract of the script I am compiling.
However, I am just getting errors.
Any assistance and/or direction will be much appreciated.
You need a column that specifies the ordering. SQL tables represent unordered sets, so there is no "last row", unless a column specifies that.
Let me assume you have one. I'll just call it ?.
Then you can use first_value():
select t.*,
first_value(wa_calc) over (partition by id order by ? desc) as wa_calc_final
from t;

Calculating user's balance with multiple cost tables

We're building a SaaS offering where a user can incur costs from various types of transactions for example:
Making phone calls
Sending SMS messages
Storing audio recordings
We have built our system to store the costs of each service, for example the call_audit table looks like:
Date Call ID Our Cost User Cost Currency Duration User ID
---------- -------- --------- --------- -------- -------- -------
2018-01-02 sm_123 0.01 0.02 USD 72 us_1
The sms_audit table looks like:
Date SMS ID Our Cost User Cost Currency User ID
---------- -------- --------- --------- -------- -------
2018-01-02 sm_123 0.01 0.02 USD us_1
Then there is a payment_audit table with user payments and refunds:
Date User ID Amount Currency Type
---------- -------- ------ -------- ----
2018-01-02 us_1 12 USD CHARGE
2018-01-02 us_1 -2 USD REFUND
We also have a user table with a balance column which we decrement when the user incurs a call, sms cost or refund. We increment it when the user pays into their account (CHARGE as above).
But going forward I'm thinking we need something more resilient than a single balance figure which gets updated in code.
One improvement is to update the balance figure with triggers instead of in code.
Another approach would be to calculate the user's total costs and payments across multiple tables and sum the lot. As the tables grow to many 1000s of transactions I can imagine this becoming a slow computation.
Another approach we thought of was to have a balance_transactions table with a debit, credit and running balance column. This of course incurs transitive dependencies between rows which isn't great if seeking a nicely normalized DB. It also means we're duplicating data, but in the real world is this an acceptable trade off?
You can avoid duplicating the data by using materialized views. Note, that updating the balance (in any way - either by the application, triggers, partial running balances) already duplicates the data. As such, you should have some validation procedures running to alert on discrepancies. And such validation procedures should do all the calculations, so they might as well populate materialized view.
However, the actual solution depends on frequency you need these data. If you, for example, fetch all the customers balances monthly for invoicing purposes, just don't duplicate them. But if you print the balance after each customer operation, e.g. in some kind of transaction confirmation (like PDF generated and e-mailed to customer), you might want to keep the running balance in a form that was presented to the customer, since he owns the balance evidence.

Calculating interest using SQL

I am using PostgreSQL, and have a table for a billing cycle and another for payments made in a billing cycle.
I am trying to figure out how to calculate interest based on how much amount was left after each billing cycle's last payment date. Problem is that every time a repayment is made, the interest has to be calculated on the amount remaining after that.
My thoughts on building this query are like this. Build data for all dates from last pay date of the billing cycle to today. Using partitioning, get the remaining amount for the first date. For second date, use amount from previous row and add interest to it, and then calculate interest on this one.
Unfortunately I am stuck just at the thought and can't figure out how to make this into a query!
Here's some sample data to make things easier to understand.
Billing Cycles:
id | ends_at
-----+---------------------
1 | 2017-11-30
2 | 2017-11-30
Payments:
amount | billing_cycle_id | type | created_at
-----------+------------------+---------+----------------------------
6000.0000 | 1 | payment | 2017-11-15 18:40:22.151713
2000.0000 | 1 |repayment| 2017-11-19 11:45:15.6167
2000.0000 | 1 |repayment| 2017-12-02 11:46:40.757897
So if we see, user made a repayment on the 19th, so amount due for interest post ends date(30th Nov 2017), is only 4000. So, from 30th to the 2nd, interest will be calculated daily on 4000. However, from the 2nd, interest needs to be calculated on 2000 only.
Interest Calculations(Today being 2017-12-04):
date | amount | interest
------------+---------+----------
2017-12-01 | 4000 | 100 // First day of pending dues.
2017-12-02 | 2100 | 52.5 // Second day of pending dues.
2017-12-03 | 2152.5 | 53.8125 // Third day of pending dues.
2017-12-04 |2206.3125| // Fourth's day interest will be added tomorrow
Your data is too sparse. It doesn't make any sense to need to write this query, because over time the query will get significantly more complicated. What happens when interest rates change over time?
The table itself (or a secondary table, depending on how you want to structure it) could have a running balance you add every time a deposit / withdrawal is made. (I suggest this table be add-only) Otherwise you're making both the calculation and accounting far harder on yourself than it should be. Even with the way you've presented the problem here, there's not enough information to do the calculation. (interest rate is missing) When that's the case, your stored procedure is going to be too complicated. Complicated means bugs, and people get irritated about bugs when you're talking about their money.

SQL SUM expression and Lock

I have a problem with right SQL solution.
Current situation:
My database contains table with bank transactions (credit and debit).
Credit transactions are signed as posivitive amount (+), and
debit transactions as negative amount (-).
Application which uses the DB is a multiuser webapp, so Transactions Table contains many rows, which reference to different users.
Some webapp actions need to check actual balance of logged user, using Transactions table and save debit Transaction (action price).
I think about architecture of this mechanism and have some questions:
Is it a good idea to calculate balance as a SUM of Transactions credits and debits each time user requests? I know it may be inefficient for db. Maybe should I save a snapshot somewhere?
How to ensure data cohesion when one user checks ""balance"" as a SUM of credit/debit transactions, and another user in the same time saves debit transaction (because he/she was faster)? I think about a pessimistic lock but what should I lock? I know that lock with aggregation (SUM) may be impossible on Postgresql (database which I use)."
Sorry for my English, I hope my problem is understandable. :)
I would consider EITHER:
Storing a balance on the account record, along with the date for which the balance is accurate.
Getting the current balance is a matter of reading the account balance, and then including any transactions since that date.
You can have a scheduled job that recalculates and timestamps that balance at an hour past midnight.
OR (and this is my preferred solution):
Every time a transaction or batch of transactions is loaded, lock the relevant account records and update them with the values from the insert as part of the same transaction.
This has the advantage of serialising access to the account, which can then help with determining whether a transaction can go ahead or not because of decisions based on the balance calculation.
If you want to avoid having the balance on the user account, something that could have a better performance, the approach I would experiment would be:
Each transaction would be related to only one account.
Each transaction would have the account balance after that transaction.
Therefore, the last transaction for that account would have the current balance.
Ex.:
TransactionId | AccountId | Datetime | Ammount | Balance
1 | 1 | 7/11/16 | 0 | 0
2 | 1 | 7/11/16 | 500 | 500
3 | 1 | 7/11/16 | -20 | 480
4 | 1 | 8/11/16 | 50 | 530
5 | 1 | 8/11/16 | -200 | 330
This way you would be able to get the account balance (last transaction with that accountId) and you would be able to provide a better view into the balance change over time.

Calculate Distinct Sums in PowerPivot

I have a transaction history that follows the below format, and I need to sum up the unique amounts per transaction.
Sample Data:
Transaction ID Transaction Date Activity Date Amount
1001 10/30/2014 11/5/2014 $50.00
1001 10/30/2014 11/7/2014 $50.00
1002 11/2/2014 11/14/2014 $100.00
1002 11/2/2014 11/17/2014 $100.00
I tried two approaches, based on the way the data is formatted, either trying to filter for unique transaction ids:
=CALUCLATE(SUM(TRANSACTION HISTORY[AMOUNT]),DISTINCT(TRANSACTION HISTORY[TRANSACTION ID]))
Or to sum up based on the earliest activity date:
=CALUCLATE(SUM(TRANSACTION HISTORY[AMOUNT]),EARLIEST(TRANSACTION HISTORY[ACTIVITY DATE]))
Both formulas result in errors though. Anyone have an a different approach for how this could be summed? The answer I'm trying to get is Sum of Unique Amount = $150.
Thanks.
The way to approach this is probably with one of the X functions which iterate over the data specified performing the calculation under that context and then summarising the results. Try this:
=SUMX(
VALUES(transaction_history[Transaction_ID]),
AVERAGE(transaction_history[Amount])
)