Generating Aging Report - sql

I need to generate an aging report using the below sample data from tblAccount.
+---------+----------+---------------+-------------------+---------------------+-------------+-----------+---------+
| Loan ID | Account | Name | Amortization Date | Amortized Principal | Paid Amount | Date Paid | Balance |
+---------+----------+---------------+-------------------+---------------------+-------------+-----------+---------+
| 2 | A0007787 | JIMMY NEUTRON | 3/9/2020 | 3823.53 | 3823.53 | 3/9/2020 | 0 |
| 2 | A0007787 | JIMMY NEUTRON | 4/9/2020 | 3823.53 | 500 | 3/9/2020 | 3323.53 |
| 2 | A0007787 | JIMMY NEUTRON | 5/9/2020 | 3823.53 | 0 | NULL | 3823.53 |
+---------+----------+---------------+-------------------+---------------------+-------------+-----------+---------+
Zero (0) paid amount and NULL Date Paid means that the amortized principal is not yet paid. Below is my desired output for specific Aging dates.
Aging A - Aging on March 12 Payment has been made on March 12 for March 9 schedule
+---------+----------+---------------+------------+------------+---------+---------+-------+-------+-----
+---------+----------+---------------+------------+------------+---------+---------+-------+-------+-------+---------------+
| Loan ID | Account | Name | Due | Payment | Balance | Current | 30 | 60 | 90 | 120 and Above |
+---------+----------+---------------+------------+------------+---------+---------+-------+-------+-------+---------------+
| 2 | A0007787 | JIMMY NEUTRON | 3,823.53 | 3,823.53 | 0 | - | - | - | - | - |
+---------+----------+---------------+------------+------------+---------+---------+-------+-------+-------+---------------+
Aging B - May 10 500.00 payment has been made on April 9 for April 9 schedule
+---------+----------+---------------+------------+----------+------------+------------+-------+-------+-------+-----------------+
| Loan ID | Account | Name | Due | Payment | Balance | Current | 30 | 60 | 90 | 120 and Above |
+---------+----------+---------------+------------+----------+------------+------------+-------+-------+-------+-----------------+
| 2 | A0007787 | JIMMY NEUTRON | 3,823.53 | 500.00 | 3,323.53 | 3,323.53 | - | - | - | - |
+---------+----------+---------------+------------+----------+------------+------------+-------+-------+-------+-----------------+
Aging C - June 10 There is remaining balance for April 9 schedule and no payment made for May 9
schdeule
+---------+----------+---------------+------------+---------+------------+-----------+------------+------------+-------+-----------------+
| Loan ID | Account | Name | Due | Payment | Balance | Current | 30 | 60 | 90 | 120 and Above |
+---------+----------+---------------+------------+---------+------------+-----------+------------+------------+-------+-----------------+
| 2 | A0007787 | JIMMY NEUTRON | 7,147.06 | 500 | 7,147.06 | - | 3,823.53 | 3,323.53 | - | - |
+---------+----------+---------------+------------+---------+------------+-----------+------------+------------+-------+-----------------+
I have looked and tried suggested solutions here, made tweeks, but it seems that it does not fit to what I wanted to produce.
Currently, I have this kind of Stored Procedure:
INSERT INTO #Aging (
Loan, ID, Account, Name, AmortizationSchedule, AmortizedPrincipal, PaidAmount, DatePaid, Balance)
SELECT Loan, ID, Account, Name, AmortizationSchedule, AmortizedPrincipal, PaidAmount, DatePaid, Balance
FROM tblAccount
Select DISTINCT Loan, ID, Account, Name, AmortizationSchedule, AmortizedPrincipal, PaidAmount, DatePaid, Balance
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) < 1 then balance else 0 end) as [Current],
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) between 1 and 30 then balance else 0 end) as [DueTo30],
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) between 31 and 60 then balance else 0 end) as [DueTo60],
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) between 61 and 90 then balance else 0 end) as [DueTo90],
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) between 91 and 120 then balance else 0 end) as [DueTo120],
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) > 120 then balance else 0 end) as [Over120]
from #Aging where balance<>0.00
order by Account
But it gives the following result,
+---------+----------+---------------+-------------+------------+-------------+-----------+-------+-------------+----+-----------------+
| Loan ID | Account | Name | Due | Payment | Balance | Current | 30 | 60 | 90 | 120 and Above |
+---------+----------+---------------+-------------+------------+-------------+-----------+-------+-------------+----+-----------------+
| 2 | A0007787 | JIMMY NEUTRON | 90,000.00 | 8,647.06 | 14,294.12 | - | - | 14,294.12 | 0 | 0 |
+---------+----------+---------------+-------------+------------+-------------+-----------+-------+-------------+----+-----------------+
It seems that it duplicate the value of due, payment and balance on the number of amortization schedule which is three (March, April, May)
Hoping for a positive response. TIA!

Your query gives the correct results once group by and sum used. Am I missing something?
Select DISTINCT [Loan ID], Account, [Name]
,sum(AmortizedPrincipal) Due, sum(PaidAmount) Payment, sum(Balance) Balance,
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) < 1 then balance else 0 end) as [Current],
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) between 1 and 30 then balance else 0 end) as [DueTo30],
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) between 31 and 60 then balance else 0 end) as [DueTo60],
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) between 61 and 90 then balance else 0 end) as [DueTo90],
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) between 91 and 120 then balance else 0 end) as [DueTo120],
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) > 120 then balance else 0 end) as [Over120]
from #Aging where balance<>0.00
GROUP BY [Loan ID], Account, [Name]
order by Account
Please check the db<>fiddle here.

Related

how to get balance sheet (debit , credit , balance) from transactions table in SQL?

if I have transactions table like that:
+----+--------+------------+-------------+--------+
| id | userID | debitAccID | creditAccID | amount |
+----+--------+------------+-------------+--------+
| 1 | 1 | 1 | 2 | 500 |
| 2 | 1 | 1 | 3 | 600 |
| 3 | 1 | 3 | 1 | 200 |
+----+--------+------------+-------------+--------+
how what query to use to get a table for account with id 1 like that:
+----+--------+------------+-------------+--------+
| debit | credit |balance |
+----+--------+------------+-------------+--------+
| | 500 | | 500 |
| | 600 | | 1100 |
| | | 200| 900 |
+----+--------+------------+-------------+--------+
900
Assuming the id column shows the correct order of transactions, you can use case and window with the default of rows between unlimited preceding and current row to get your output:
select id, user_id,
case when user_id = debit_acc_id then amount else 0 end as debit,
case when user_id = credit_acc_id then amount else 0 end as credit,
sum(case when user_id = debit_acc_id then amount else 0 end) over w
- sum(case when user_id = credit_acc_id then amount else 0 end) over w as balance
from transactions
where user_id = 1
window w as (partition by user_id order by id)
order by user_id, id;
db<>fiddle here

Slicing account balance data in BigQuery to generate a debit report

I have a collection of account balances over time:
+-----------------+------------+-------------+-----------------------+
| account_balance | department | customer_id | timestamp |
+-----------------+------------+-------------+-----------------------+
| 5 | A | 1 | 2019-02-12T00:00:00 |
| -10 | A | 1 | 2019-02-13T00:00:00 |
| -35 | A | 1 | 2019-02-14T00:00:00 |
| 20 | A | 1 | 2019-02-15T00:00:00 |
+-----------------+------------+-------------+-----------------------+
Each record shows the total account balance of a customer at a specified timestamp. The account balance increases e.g. to 20 from -35, when a customer tops-up his account with 55. As a customer uses a services, his account balances decreases e.g. from 5 to -10.
I want to aggregate this data in two ways:
1) Get the debit, credit and balance (credit-debit) of a department per month and year. The results from April should be a summary of all previous months:
+---------+--------+-------+------------+-------+--------+
| balance | credit | debit | department | month | year |
+---------+--------+-------+------------+-------+--------+
| 5 | 10 | -5 | A | 1 | 2019 |
| 20 | 32 | -12 | A | 2 | 2019 |
| 35 | 52 | -17 | A | 3 | 2019 |
| 51 | 70 | -19 | A | 4 | 2019 |
+---------+--------+-------+------------+-------+--------+
A customer's account balance might not change every month. There might be account balance records of customer 1 in February, but not March.
Notes towards the solution:
use EXTRACT(MONTH from timestamp) month
use EXTRACT(YEAR from timestamp) year
GROUP BY month, year, department
2) Get the change of debit, credit and balance of a department by date.
+---------+--------+-------+------------+-------------+
| balance | credit | debit | department | date |
+---------+--------+-------+------------+-------------+
| 5 | 10 | -5 | A | 2019-01-15 |
| 15 | 22 | -7 | A | 2019-02-15 |
| 15 | 20 | -5 | A | 2019-03-15 |
| 16 | 18 | -2 | A | 2019-04-15 |
+---------+--------+-------+------------+-------------+
51 70 -19
When I create a SUM of the deltas, I should get the same values as the last row from results in 1).
Notes towards the solution:
use account_balance - LAG(account_balance) OVER(PARTITION BY department ORDER BY timestamp ASC) delta to compute deltas
Your question is unclear, but it sounds like you want to get the outstanding balance at any given point in time.
The following query does this for 1 point in time.
with calendar as (
select cast('2019-06-01' as timestamp) as balance_calc_ts
),
most_recent_balance as (
select customer_id, balance_calc_ts,max(timestamp) as most_recent_balance_ts
from <table>
cross join calendar
where timestamp < balance_calc_ts -- or <=
group by 1,2
)
select t.customer_id, t.account_balance, mrb.balance_calc_ts
from <table> t
inner join most_recent_balance mrb on t.customer_id = mrb.customer_id and t.timestamp = mrb.balance_calc_ts
If you need to calculate it at a series of points in time, you will need to modify the calendar CTE to return more dates. This is the beauty of CROSS JOINS in BQ!

SQL last 15 months of sales grouped by customer

I would like to output in sql a table that contains the monthly sales per customer. Each column should correspond to another month.
First column should be current month example my sql columns are:
customer
invoicedate
sales
Original table looks like this:
+------------+------------+---------+
| Customer | invdate | sales |
+------------+------------+---------+
| Best Buy | 03-12-2019 | 433 |
| Walmart | 03-15-2019 | 543 |
| Home Depot | 12-12-2018 | 32 |
+------------+------------+---------+
Desired Output:
+------------+----------+--------+--------+--------+--------+----------+
| Customer | March 19 | Feb 19 | Jan 19 | Dec 18 | Nov 18 | Oct 18 |
+------------+----------+--------+--------+--------+--------+----------+
| Home Depot | 100 | 300 | 244 | 32 | 322 | 43 |
| Walmart | 543 | 222 | 234 | 12 | 234 | 34 |
| Bestbuy | 433 | 323 | 323 | 23 | 433 | 34 |
+------------+----------+--------+--------+--------+--------+----------+
You can use group by, sum, and case to good effect, like this:
select
customer,
sum(case when year(invdate) = year(getdate) and month(invdate) = month(getdate()) then sales else o end),
sum(case when year(invdate) = year(dateadd(m,1,getdate))
and month(invdate) = month(dateadd(m,1,getdate())) then sales else o end),
sum(case when year(invdate) = year(dateadd(m,2,getdate))
and month(invdate) = month(dateadd(m,2,getdate())) then sales else o end),
sum(case when year(invdate) = year(dateadd(m,3,getdate))
and month(invdate) = month(dateadd(m,3,getdate())) then sales else o end),
sum(case when year(invdate) = year(dateadd(m,4,getdate))
and month(invdate) = month(dateadd(m,4,getdate())) then sales else o end),
sum(case when year(invdate) = year(dateadd(m,5,getdate))
and month(invdate) = month(dateadd(m,5,getdate())) then sales else o end)
from tableyoudidnotgivethenameof
group by customer

sql Group by columns to the same row without join

I have grouped sales from a sales view with sales below using
Select id, name, Count(*) as [Sales], product, amount
from vwSales
Group by
id,name, product, amount
ID | Name | Sales | Product | Amount
1 | Bob | 4 | Fridge | 40
1 | Bob | 12 | Washer | 120
2 | Anne | 5 | Fridge | 50
2 | Anne | 4 | Washer | 40
Is it possible to group these in to one row without using a join? So table looks something like
ID | Name | Fridge Sales | fridge Amt | Washer sales | washer amt
1 | Bob | 4 | 40 | 12 | 120
2 | Anne | 5 | 50 | 4 | 40
You can do conditional aggregation :
select id, name,
sum(case when Product = 'Fridge' then 1 else 0 end) as [Fridge Sales],
sum(case when Product = 'Fridge' then Amount else 0 end) as [fridge Amt],
sum(case when Product = 'Washer' then 1 else 0 end) as [Washer Sales],
sum(case when Product = 'Washer' then Amount else 0 end) as [Washer Amt]
from vwSales
Group by id, name;

SQL column sum and difference

my table, I want to create three columns in single-column, reprinted now.
id | date | type | total
------ | ------ | ------ | -----
1 | 01.10.2016| Paypal | 50
2 | 03.10.2016| credit | 40
3 | 05.10.2016| Cash | 50
4 | 06.10.2016| payment| 100
5 | 07.10.2016| Cash | 20
6 | 15.10.2016| Skrill | 10
7 | 18.10.2016| payment| 20
8 | 19.10.2016| Paypal | 10
9 | 19.10.2016| payment| 20
10 | 22.10.2016| Cash | 40
11 | 23.10.2016| Skrill | 10
my table, I want to create three columns in single-column, reprinted now.
SELECT id,date,type,total
(select (
sum(case when type="Paypal" then total else 0 end)+
sum(case when type="credit" then total else 0 end))+
sum(case when type="Cash" then total else 0 end) ) as receiv,
(Select(
sum(case when type="payment" then total else 0 end)) AS payment,
(Select sum(receiv -payment) FROM totals t2
WHERE (t2.date <= t1.date) and (t2.id <= t1.id) order by t1.date) AS remainder
FROM totals t1
group by date, type
order by id,date
--
The following query for the sql code?
Type = "Paypal, credit, Cash" sums "receiv" sums and Type = "payment" sums will be added to the "remainder" column.
id | date | type | receiv| payment| remainder
------ | ------ | ------ | ------| ------ | ------
1 | 01.10.2016| Paypal | 50 | 0 | 50
2 | 03.10.2016| credit | 40 | 0 | 90
3 | 05.10.2016| Cash | 50 | 0 | 140
4 | 06.10.2016| payment| 0 | 100 | 40
5 | 07.10.2016| Cash | 20 | 0 | 60
6 | 15.10.2016| Skrill | 10 | 0 | 70
7 | 18.10.2016| payment| 0 | 20 | 50
8 | 19.10.2016| Paypal | 10 | 0 | 60
9 | 19.10.2016| payment| 0 | 20 | 40
10 | 22.10.2016| Cash | 40 | 0 | 80
11 | 23.10.2016| Skrill | 10 | 0 | 90
Running total is easier in other databases which have analytical functions. In MySQL, you can do this with a correlated sub-query.
select id,dt,type,
case when type <> 'payment' then total else 0 end receiv,
case when type = 'payment' then total else 0 end payment,
case when type <> 'payment' then total else 0 end
- case when type = 'payment' then total else 0 end
+ coalesce((select sum(case when type <> 'payment' then total else 0 end)
- sum(case when type = 'payment' then total else 0 end)
from yourtable where id < y.id),0)
from yourtable y
Sample Demo