SSRS summary of nested groups at outer group footer - reporting-services

I have a report ouput like this,
it has nested groups, outer group is on Business Partners and the inner one is on Currency Code.
Busines Partner1
Opening Balance for USD as of 2013-10-01
Transaction 1..
Transaction n..
USD Totals
Balance for EUR as of 2013-10-01
Transaction 1..
Transaction n..
EUR Totals
Busines Partner2
Opening Balance for USD as of 2013-10-01
Transaction 1..
Transaction n..
USD Totals
Balance for EUR as of 2013-10-01
Transaction 1..
Transaction n..
EUR Totals
What I need is on Business Partner Group Footer, I'd like to display overall outstanding balances for each currency code. Something like;
Busines Partner1
Opening Balance for USD as of 2013-10-01
Transaction 1..
Transaction n..
USD Totals
Balance for EUR as of 2013-10-01
Transaction 1..
Transaction n..
EUR Totals
(Assume below section is Business Partner1 Group Footer)
Currency, Opening Balance, Sum of In Period, Overall
USD 200.00 300.00 500
EUR 150.00 400.00 550
Total 1050
Busines Partner2
Opening Balance for USD as of 2013-10-01
Transaction 1..
Transaction n..
USD Totals
Balance for EUR as of 2013-10-01
Transaction 1..
Transaction n..
EUR Totals
(Assume below section is Business Partner2 Group Footer)
Currency, Opening Balance, Sum of In Period, Overall
USD 100.00 300.00 400
EUR 250.00 300.00 550
Total 950
Question is how can I achieve this?
I am pulling data from an SP, with opening balances for a given date.
Number of currencies are not known beforehand.
And the report has 2 groups, outer group is on Biz.PartnerId inner one is on currency
code.
SSRS 2008 R2 ( I can upgrade to latest and greatest if this is
an issue to consider.)

I think that you just have to structure your groups right..
based on the following sample data:
SELECT 'BusinessPartner1' BusinessPartner, 'EUR' CurrencyType, 100 Amount, 122 TotalSpend UNION
SELECT 'BusinessPartner1' BusinessPartner, 'GBP' CurrencyType, 111 Amount, 301 TotalSpend UNION
SELECT 'BusinessPartner2' BusinessPartner, 'EUR' CurrencyType, 81 Amount, 191 TotalSpend UNION
SELECT 'BusinessPartner2' BusinessPartner, 'GBP' CurrencyType, 13 Amount, 93 TotalSpend UNION
SELECT 'BusinessPartner2' BusinessPartner, 'USD' CurrencyType, 30 Amount, 32 TotalSpend UNION
SELECT 'BusinessPartner3' BusinessPartner, 'GBP' CurrencyType, 78 Amount, 42 TotalSpend UNION
SELECT 'BusinessPartner3' BusinessPartner, 'USD' CurrencyType, 210 Amount, 61 TotalSpend UNION
SELECT 'BusinessPartner3' BusinessPartner, 'EUR' CurrencyType, 12 Amount, 71 TotalSpend
If you structure your groups like this, (1 parent, 1 child, 1 adjacent to child):
Then you get the below output, which I think is the same sort of thing that you're after. To get exactly what you need I think that you would also need a details child group on each of the adjacent groups

Related

SQL How to get avg per day

Hello I have a table that looks like this:
Train
Date
Passengers
1
2020-01-01
100
2
2020-01-01
50
3
2020-01-01
25
1
2020-01-02
90
2
2020-01-02
30
3
2020-01-02
40
1
2020-01-03
80
2
2020-01-03
20
3
2020-01-03
60
I need to get average per day, but because dates are same per 3 rows in Date with this code:
SELECT Date, Train, avg(Passengers) AS Avg_Passengers
FROM trainstation
WHERE Date != Date + 1 -- I know it's wrong like this but I don't know how to make a condition like this
group by Date, Train
I get an error and without the WHERE I get same table but in float type the number of passengers
Result that I want:
Date
Avg_Passengers
2020-01-01
58.333
2020-01-02
46.666
2020-01-03
53.333
If you want the average passengers per train, you would use:
SELECT Train, avg(Passengers) AS Avg_Passengers
FROM trainstation
GROUP BY Train;
If you want the average across all trains per day:
SELECT Date, avg(Passengers) AS Avg_Passengers
FROM trainstation
GROUP BY Date;
try this :
from
(
select Date, Train, sum(passenger) as 'price'
from table
group by Date, Train
)
group by Date
I think this will work for you :
select Datepart(day, Date), avg(passengers)
from yourTable
group by Datepart(day, Date)

How to get SUM of a column of a child table when query parent table?

I have two tables
Account Table (account)
id name
1 Account 1
2 Account 2
3 Account 3
4 Account 2
Transaction Table (transaction)
id account_id type amount datetime
1 1 credit 500 2020-04-01 06:00:00
2 1 credit 300 2020-04-01 06:00:00
3 2 credit 100 2020-04-01 06:00:00
4 2 debit 50 2020-04-01 06:00:00
5 1 debit 600 2020-04-01 06:00:00
6 3 credit 1000 2020-04-01 06:00:00
7 1 credit 100
My target is to get account id, name, balance in one query. The balance will be calculated from the transaction table as SUM of Credit Amount - SUM of Debit Amount for a given account.
Target Output
id name balance
1 Account 1 300
2 Account 2 50
3 Account 3 1000
4 Account 4 0
Possible Query
SELECT id, name, ((SELECT SUM(amount) FROM transaction WHERE type = 'credit' AND account_id = {ACCOUNT_ID} ) - (SELECT SUM(amount) FROM transaction WHERE type = 'debit' AND account_id = {ACCOUNT_ID} )) as balance
Is it possible to do this in one query and If yes How to do it.
You could do the aggregation in a derived table to avoid the issues of having to group by a lot of fields in the top level. For example:
SELECT a.id, a.name, COALESCE(b.balance, 0) AS balance
FROM account a
LEFT JOIN (
SELECT account_id,
SUM(CASE WHEN type='credit' THEN amount ELSE 0 END) -
SUM(CASE WHEN type='debit' THEN amount ELSE 0 END) AS balance
FROM transaction
GROUP BY account_id
) b ON b.account_id = a.id
Output:
id name balance
1 Account 1 300
2 Account 2 50
3 Account 3 1000
4 Account 2 0
Demo on SQLFiddle
You need a left join of account to transaction so you can group by each account and conditionally sum the amount depending on the type:
select
a.id, a.name,
sum(case when type = 'credit' then 1 else -1 end * coalesce(t.amount, 0)) balance
from account a left join transaction t
on t.account_id = a.id
group by a.id, a.name

Amazon Redshift query to get delinquent amount and days past due at the end of month

Changing the question because of a misunderstanding in use case.
Amazon Redshift Query for the following problem statement.
The data structure:
id - primary key
acc_id - id unique to a loan account (this id will be same for all
emi's for a particular loan account, this maybe repeated 6 times or
12 times based on loan tenure which can be 6 months or 12 months
respectively)
status - PAID or UNPAID (the emi's unpaid are followed my unpaid
emi's only)
s_id - just a scheduling id which would be consecutive numbers for a
a particular loan id
due_date - the due date for that particular emi
principal - amount that is due
The table:
id acc_id status s_id due_date principal
9999957 10003 PAID 102 2018-07-02 12:00:00 4205
9999958 10003 UNPAID 103 2018-08-02 12:00:00 4100
9999959 10003 UNPAID 104 2018-09-02 12:00:00 4266
9999960 10003 UNPAID 105 2018-10-02 12:00:00 4286
9999962 10004 PAID 106 2018-07-02 12:00:00 3200
9999963 10004 PAID 107 2018-08-02 12:00:00 3100
9999964 10004 UNPAID 108 2018-09-02 12:00:00 3266
9999965 10004 UNPAID 109 2018-10-02 12:00:00 3286
The use case -
The unpaid amount becomes delinquent (overdue) after the due_date.
So I need to calculate delinquent amount at the end of every month from the first due_date in this case is 2nd July to last due_date (assume it to be 2nd November which is the current month)
I also need to calculate days past due at the end of that month.
Illustration from the above data:
From the sample data provided, no EMI is due at the end of July so amount delinquent is 0
But at the end of August - the id 9999958 is due - as of 31st August
the amount delinquent is 4100 and days past due is 29 (31st August minus 2nd August)
The catch: I need to calculate this for the loan (acc_id) and not the emi.
To further explain, A first EMI will be 29 days due on 1st month and 59 days due on second month, also second EMI will be 29 days due on second month. But I need this at loan level (acc_id).
The same example continued for 30th september, the acc_id 10003 is due since 2nd August so as of 30th September the due amount is 8366 (4100 + 4266) and DPD (days_past_due) is 59 (29 + 30).
Also acc_id 10004 is due 3100 and DPD is 28 (30th september - 2nd september).
The final output would be something like this:
Month_End DPD_Band Amount
2018/08/31 0-29 4100
2018/08/31 30-59 0
2018/08/31 60-89 0
2018/08/31 90+ 0
2018/09/30 0-29 3100
2018/09/30 30-59 8366
2018/09/30 60-89 0
2018/09/30 90+ 0
Query attempt: DPD bands can be created based on case statements on delinquent days. I need real help in first creating End-of-months and then finding the portfolio level amounts as explained above for different delinquent days.
Edited to be RedShift compatible after the op clarified which RDBMS. (MySQL would need a different answer)
The following creates one record for each month between your first record, and the end of last month.
It then joins on to your unpaid records, and the aggregation chooses which bracket to put the results in to.
WITH
first_month AS
(
SELECT LAST_DAY(MIN(due_date)) AS end_date FROM yourTable
),
months AS
(
SELECT
LAST_DAY(ADD_MONTHS(first_month.end_date, s.id)) AS end_date
FROM
first_month
CROSS JOIN
generate_series(
1,
DATEDIFF(month, (SELECT end_date FROM first_month), CURRENT_DATE)
)
AS s(id)
),
monthly_delinquents AS
(
SELECT
yourTable.*,
months.end_date AS month_end_date,
DATEDIFF(DAY, yourTable.due_date, months.end_date) AS days_past_due
FROM
months
LEFT JOIN
yourTable
ON yourTable.status = 'UNPAID'
AND yourTable.due_date < months.end_date
)
SELECT
month_end_date,
SUM(CASE WHEN days_past_due >= 00 AND days_past_due < 30 THEN principal ELSE 0 END) AS dpd_00_29,
SUM(CASE WHEN days_past_due >= 30 AND days_past_due < 60 THEN principal ELSE 0 END) AS dpd_30_59,
SUM(CASE WHEN days_past_due >= 60 AND days_past_due < 90 THEN principal ELSE 0 END) AS dpd_60_89,
SUM(CASE WHEN days_past_due >= 90 THEN principal ELSE 0 END) AS dpd_90plus
FROM
monthly_delinquents
GROUP BY
month_end_date
ORDER BY
month_end_date
That said, normally the idea of pivoting things like this is a bad idea. What happens when something is a year past due? It just sits in the 90plus category and never moves. And, if you want to expand it you need to change the query and any other query you ever write that depends on it.
Instead, you could normalise your output...
WITH
first_month AS
(
SELECT LAST_DAY(MIN(due_date)) AS end_date FROM yourTable
),
months AS
(
SELECT
LAST_DAY(ADD_MONTHS(first_month.end_date, s.id)) AS end_date
FROM
first_month
CROSS JOIN
generate_series(
1,
DATEDIFF(month, (SELECT end_date FROM first_month), CURRENT_DATE)
)
AS s(id)
),
monthly_delinquents AS
(
SELECT
yourTable.*,
months.end_date AS month_end_date,
DATEDIFF(DAY, yourTable.due_date, months.end_date) AS days_past_due
FROM
months
LEFT JOIN
yourTable
ON yourTable.status = 'UNPAID'
AND yourTable.due_date < months.end_date
)
SELECT
month_end_date,
(days_past_due / 30) * 30 AS days_past_due_band,
SUM(principal) AS total_principal,
COUNT(*) AS total_rows
FROM
monthly_delinquents
GROUP BY
month_end_date,
(days_past_due / 30) * 30
ORDER BY
month_end_date,
(days_past_due / 30) * 30

Joining 3 tables with multiples event associated to the same unique ID in each table with Google Cloud SQL

I have three tables in Google Cloud SQL :
Event table :
id Name Date
A10117 foo 2017-01-01 0:00:00
A10617 bar 2017-01-06 0:00:00
A11017 barfoo 2017-01-10 0:00:00
A11317 foofoo 2017-01-13 0:00:00
A11417 barbar 2017-01-14 0:00:00
A12017 foobar 2017-01-20 0:00:00
Income table :
id Income
A10117 1000
A10117 200
A10617 5000
A11017 3000
A11317 1500
A11317 560
A11417 2000
A12017 1500
Expenses table :
id Expenses
A10117 80
A10617 25
A10617 75
A11017 99
A11317 123
A11317 45
A11417 34
A11417 95
A12017 678
I want the output to be one big table where each event is only one row with Income and Expenses properly sum.
for example in the final output I should have one row for ID A10617 :
id Name Date Income Expenses
A10617 bar 2017-01-06 0:00:00 5000 100
etc...
I've built some query trying to consolidate all this using WHERE clause but I have some duplicate in my final output.
So my question is : How can I efficiently consolidate these 3 tables in one query ? My understand is I need to consolidate each table separately first one after another. I don't know how to do it.
My ideal query would be something like this :
SELECT id,Name,Date,sum(Income),sum(Expenses)
FROM Event e, Income i, Expenses ee
WHERE e.id = i.id = ee.id
GROUP BY id,Name,Date
select e.id, (select sum(Income) from income where id=e.id) as income, sum(ex.Income) as expenses from event as e inner join expenses as ex on e.id=ex.id group by e.id
This assumes all event ids are there in both income and expenses. If it is not the case change inner join to left join
Edit:
Little faster query:
select e.id, (select sum(Income) from income where id=e.id) as income, (select sum(Income) from expenses where id=e.id) as expenses from event as e

SQL / MySQL: Sum all amounts for respective month

I've got a table in my database which looks like this:
payment_id customer_id amount payment_date
1 32 20.00 2005-01-25 11:30:37
2 32 10.00 2005-01-26 11:30:37
3 11 25.00 2005-03-25 11:30:37
Now I want to sum all amounts a customer (customer_id) made in the respective month.
I need a query that looks which month exists and which customers have an entry for this month.
The result should look like this:
customer_id month amount
32 01 30.00
11 03 25
I tried this:
SELECT DISTINCT month(payment_date) AS month, customer_id, sum(amount) AS amount
FROM table
But it just sums all amount values of the whole table.
You have to use a GROUP BY query:
SELECT
customer_id,
month(payment_date) as month,
sum(amount) as total_amount
FROM
tablename
GROUP BY
customer_id,
month(payment_date)