Sql query Solution - sql

I have a query as follows.
select strftime('%Y-%m',A.traDate) as Month,sum(A.TraAmt) as Total,C.GroupType from
TransactionTbl A left join TransactionCategory B on A.CategoryID = B.CategoryID left join
CategoryGroup C on B.CatGRoupID=C.CatGRoupID where A.UserID=1 and A.ProfileID=1 and
date(A.TraDate) between date('2009-12-01') and date('2010-11-01') group by C.GroupType,
strftime('%m',A.traDate) order by Month
Above query gives result as follows,
Month Total C.GroupType
----- ----- -----------
2009-12 4100 Expense
2009-12 8000 Income
2010-01 200 Expense
2010-01 2000 Income
2010-02 3500 Expense
2010-02 7500 Income
I want solution like this.
Month Income Expense
----- ----- -----------
2009-12 8000 4100
2010-01 8000 200
2010-02 7500 3500
I am trying hard to get output like this, but I could find any kind of solution.

This is one way of achieving what you want:
SELECT
T1.Month,
SUM(CASE T1.GROUPTYPE WHEN 'Income' THEN T1.TOTAL ELSE 0 END) AS Income,
SUM(CASE T1.GROUPTYPE WHEN 'Expense' THEN T1.TOTAL ELSE 0 END) AS Expense
FROM (/* Your query here */) AS T1
GROUP BY T1.Month

Related

Aggregate before and after a date column

I have two tables: db.transactions and db.salesman, which I would like to combine in order to create an output that has aggregated sales before each salesman's hire date and after each salesman's hire date.
select * from db.transactions
index sales_rep sales trx_date
1 Tom 200 9/18/2020
2 Jerry 435 6/21/2020
3 Patrick 1400 4/30/2020
4 Tom 560 5/24/2020
5 Francis 240 1/2/2021
select * from db.salesman
index sales_rep hire_date
1 Tom 8/19/2020
2 Jerry 1/28/2020
3 Patrick 4/6/2020
4 Francis 9/4/2020
I would like to aggregate sales from db.transactions before and after each sales rep's hire date.
Expected output:
index sales_rep hire_date agg_sales_before_hire_date agg_sales_after_hire_date
1 Tom 8/19/2020 1200 5000
2 Jerry 1/28/2020 500 900
3 Patrick 4/6/2020 5000 300
4 Francis 9/4/2020 2900 1500
For a single sales rep, to calculate the agg_sales_before_hire_date is likely:
select tx.sales_rep, tx.sum(sales)
from db.transactions tx
inner join db.salesman sm on sm.sales_rep = tx.sales_rep
where hire_date < '8/19/2020' and sales_rep = 'Tom'
group by tx.sales_rep
PostGRESQL. I am also open to the idea of doing it into Tableau or Python.
Using CROSS JOIN LATERAL
select
sa.sales_rep, sa.hire_date,
l.agg_sales_before_hire_date,
l.agg_sales_after_hire_date
from salesman sa
cross join lateral
(
select
sum(tx.sales) filter (where tx.trx_date < sa.hire_date) agg_sales_before_hire_date,
sum(tx.sales) filter (where tx.trx_date >= sa.hire_date) agg_sales_after_hire_date
from transactions tx
where tx.sales_rep = sa.sales_rep
) l;
Use conditional aggregation:
select tx.sales_rep,
sum(case when tx.txn_date < sm.hire_date then sales else 0 end) as before_sales,
sum(case when tx.txn_date >= sm.hire_date then sales else 0 end) as after_sales
from db.transactions tx inner join
db.salesman sm
on sm.sales_rep = tx.sales_rep
group by tx.sales_rep;
EDIT:
In Postgres, you would use filter for the logic:
select tx.sales_rep,
sum(sales) filter (where tx.txn_date < sm.hire_date) as before_sales,
sum(sales) filter (where tx.txn_date >= sm.hire_date then sales) as after_sales

How to calculate and update subtotal in SQL Server table

I have a SQL Server table in following format: Type column is to indicate whether row is Subtotal or line level value.
If type is 1, then it is line level cost, and if type is 2, then it is subtotal and if type is 3, then it is grand total.
Category Subcategory Option1 Option2 Option3 Option4 Type
----------------------------------------------------------------------------
Insurance Insurance Cost 10 20 30 40 1
Insurance Insurance Tax 10 20 30 40 1
Insurance Subtotal 0 0 0 0 2
Finance Finance Cost 10 20 30 40 1
Finance Finance Tax 10 20 30 40 1
Finance Subtotal 0 0 0 0 2
GrandTotal GrandTotal 0 0 0 0 3
----------------------------------------------------------------------------
I want to update rows with subtotal with line level subtotal of respective category and grand total with line level total
Category Subcategory Option1 Option2 Option3 Option4 Type
----------------------------------------------------------------------------
Insurance Insurance Cost 10 20 30 40 1
Insurance Insurance Tax 10 20 30 40 1
Insurance Subtotal 20 40 60 80 2
Finance Finance Cost 10 20 30 40 1
Finance Finance Tax 10 20 30 40 1
Finance Subtotal 20 40 60 80 2
GrandTotal GrandTotal 40 80 120 160 3
----------------------------------------------------------------------------
How can I calculate and update these rows?
Awaiting for your reply.
Thanks.
I think cube extension for group by best suites for your case. Consider :
select distinct max(Category) as Category, Subcategory,
sum(Option1) as Option1
sum(Option2) as Option2,
sum(Option3) as Option3,
sum(Option4) as Option4
from t
where type = 1
group by cube(Category,Subcategory)
order by Category, Subcategory desc;
Rextester Demo "This is for Option1 column only, expandable for other options"
P.S. it's illogical to store a computable data in a table, that could already exist as basic data in that table as #Dougie pointed out.
You are trying to do an update, so that is a bit tricky. I think this will do the trick:
update t
set option1 = (case t.subcategory
when 'Subtotal' then subtotal.option1
when 'GrandTotal' then grandtotal.option1
else option1
end),
option2 = (case t.subcategory
when 'Subtotal' then subtotal.option2
when 'GrandTotal' then grandtotal.option2
else option2
end),
option3 = (case t.subcategory
when 'Subtotal' then subtotal.option3
when 'GrandTotal' then grandtotal.option3
else option3
end),
option4 = (case t.subcategory
when 'Subtotal' then subtotal.option4
when 'GrandTotal' then grandtotal.option4
else option4
end)
from t cross apply
(select category, sum(option1) as option1, sum(option2) as option2,
sum(option3) as option3)
from t t2
where t2.category = t.category
) subtotal cross join
(select category, sum(option1) as option1, sum(option2) as option2,
sum(option3) as option3)
from t t2
) grandtotal
where t.subcategory in ('Subtotal', 'GrandTotal');

Rolling Sum (4 Months)

I have been struggeling with building a query in access that calculates a "rolling 4 months" of sales data. I have been experimenting with DSUM, but I only seem to be able to get the subtotal or running total for a specific group (not a moving total). I have tried to illustrate what I am trying to do below.
Date Product Value Rolling_4_Month_Sum
January A 100 100
February A 200 300
March A 300 600
April A 300 900
May A 200 1000
June A 400 1200
July A 500 1400
August A 700 1800
Is it possible to make a running total for 4 rows/months only?
SELECT
a.Date,
a.Product,
a.Value,
SUM(b.value)
FROM
Table a
INNER JOIN Table b ON a.Product=b.Product
AND b.Date <= a.Date
AND b.Date >= DateAdd("q",1, a.Date)
GROUP BY
a.Date, a.Product
This should work in my opinion.
Table a is your "single month" row date.
Table b is self join to retrieve the last 4 predecessing months. It is done by adding b.Date >= DateAdd("q",1, a.Date) as self-join criteria.
Here is a nice example of how these kinds of things work.
Data:
OrderDetailID OrderID ProductID Price
1 1234 1 $5.00
2 1234 2 ($2.00)
3 1234 3 $4.00
4 1235 1 $5.00
5 1235 3 $4.00
6 1235 5 $12.00
7 1235 2 ($2.00)
SQL:
SELECT OD.OrderDetailID, OD.OrderID, OD.ProductID, OD.Price, (SELECT Sum(Price) FROM tblOrderDetails
WHERE OrderDetailID <= OD.OrderDetailID) AS RunningSum
FROM tblOrderDetails AS OD;

sum result is being multiplied by number of rows in oracle

I have a view named b_balance which returns the following records:
SECURITIES_CODE BUY_SELL_FLAG C_BALANCE P_BALANCE
--------------- ------------- --------- ---------
10042 BUY 200 0
10042 BUY 500 0
10042 SELL 200 0
10042 BUY 0 5000
10042 SELL 0 2500
10043 BUY 300 0
10043 SELL 0 2500
and another view named as t_balance which returns the following records:
SECURITIES_CODE BUY_SELL_FLAG C_BALANCE P_BALANCE
--------------- ------------- --------- ---------
10042 BUY 0 5000
10043 BUY 300 0
10042 SELL 200 0
10042 SELL 0 2500
10043 SELL 0 2500
10042 BUY 200 0
10042 BUY 500 0
Now the problem occurs, when I execute my SQL
SELECT TO_CHAR(to_date('20170801','yyyyMMdd'), 'MM/dd/yyyy') AS TRADE_DATE,
b.securities_code AS SECURITIES_CODE,
b.buy_sell_flag AS SIDE,
SUM(NVL(t.c_balance,0)) AS C_t_balance,
SUM(NVL(b.c_balance,0)) AS C_b_balance,
SUM(NVL(t.c_balance,0)) - SUM(NVL(b.c_balance,0)) AS C_DIFFERENCE,
SUM(NVL(t.p_balance,0)) AS P_t_balance,
SUM(NVL(b.p_balance,0)) AS P_b_balance,
SUM(NVL(t.p_balance,0)) - SUM(NVL(b.p_balance,0)) AS P_DIFFERENCE
FROM b_balance b
FULL OUTER JOIN t_balance t
ON b.securities_code = t.securities_code
AND b.buy_sell_flag = t.buy_sell_flag
GROUP BY b.securities_code,
b.buy_sell_flag
ORDER BY SECURITIES_CODE,
SIDE ;
this returns the following records:
TRADE_DATE SECURITIES_CODE SIDE C_T_BALANCE C_B_BALANCE C_DIFFERENCE P_T_BALANCE P_B_BALANCE P_DIFFERENCE
---------- --------------- ---- ----------- ----------- ------------ ----------- ------------ ------------
08/01/2017 10042 BUY 2100 2100 0 15000 15000 0
08/01/2017 10042 SELL 400 400 0 5000 5000 0
08/01/2017 10043 BUY 300 300 0 0 0 0
08/01/2017 10043 SELL 0 0 0 2500 2500 0
that means the result is being multiplied by number of rows.
I checked on Stack overflow and did't find anything wrong according to this answer.
So what is the wrong in my SQL?
you should join the aggregated result (not aggregate the joined values)
SELECT TO_CHAR(to_date('20170801','yyyyMMdd'), 'MM/dd/yyyy') AS TRADE_DATE,
t1.SECURITIES_CODE,
t1.SIDE,
t1.C_b_balance,
t1.P_b_balance,
t2.C_t_balance,
t2.P_t_balance,
from (
SELECT
b.securities_code AS SECURITIES_CODE,
b.buy_sell_flag AS SIDE,
SUM(NVL(b.c_balance,0)) AS C_b_balance,
SUM(NVL(b.p_balance,0)) AS P_b_balance,
FROM b_balance b
GROUP BY b.securities_code, b.buy_sell_flag ) t1
left join (
SELECT
t.securities_code AS SECURITIES_CODE,
t.buy_sell_flag AS SIDE,
SUM(NVL(t.c_balance,0)) AS C_t_balance,
SSUM(NVL(t.p_balance,0)) AS P_t_balance,
FROM t_balance t
GROUP BY t.securities_code, t.buy_sell_flag
) on t1.securities_code = t2.securities_code and t1.buy_sell_flag = t2.buy_sell_flag
When working with aggregates from different tables, aggregate before joining:
select
date '2017-08-01' as trade_date,
securities_code as securities_code,
buy_sell_flag as side,
nvl(t.sum_c_balance, 0) as c_t_balance,
nvl(b.sum_c_balance, 0) as c_b_balance,
nvl(t.sum_c_balance, 0) - nvl(b.sum_c_balance, 0) as c_difference,
nvl(t.sum_p_balance, 0) as p_t_balance,
nvl(b.sum_p_balance, 0) as p_b_balance,
nvl(t.sum_p_balance, 0) - nvl(b.sum_c_balance, 0) as p_difference
from
(
select
securities_code,
buy_sell_flag,
sum(c_balance) as sum_c_balance,
sum(p_balance) as sum_p_balance
from b_balance
group by securities_code, buy_sell_flag
) b
full outer join
(
select
securities_code,
buy_sell_flag,
sum(c_balance) as sum_c_balance,
sum(p_balance) as sum_p_balance
from t_balance
group by securities_code, buy_sell_flag
) t using (securities_code, buy_sell_flag)
order by securities_code, buy_sell_flag;

Getting value repeated for next year if value is recurring

I have a record for project and release number and I need to repeat the row in next year if value is recurring.
First image is showing the data that I have it
My expected output is:
Explanation of output: In year 2017 value_type ITA has frequency as Recurring so, This value should be repeated in all next year(i.e 2018, 2019 and 2020). like that in year 2018 OC and PA is recurring so it also need to repeated in 2019 and 2020.
For that I created a new view for only recurring value and tried to join that view with base table. But it is not giving me proper result.
Can anyone please help me with this?
Thanks in advance..
DECLARE #EndYear INT =2020 --Also you can get from data by MAX(Year)
;WITH tb(PROJECT_ID,RELEASE_NO,[YEAR],VALUE_TYPE,VAL_DES,COST,RUN_TATE,FREQUENCY)
AS(
SELECT 111,1,2016,'IT','EXPENSE',0,NULL,NULL UNION
SELECT 111,1,2016,'IR','INCOME',10000,NULL,NULL UNION
SELECT 111,1,2016,'OC','EXPENSE',-200000,NULL,NULL UNION
SELECT 111,1,2016,'Vendor','EXPENSE',-5000,NULL,NULL UNION
SELECT 111,1,2017,'BC','INCOME',200000,NULL,NULL UNION
SELECT 111,1,2017,'ITA','INCOME',5000,5000,'Recurring' UNION
SELECT 111,1,2017,'OC','EXPENSE',-200000,NULL,NULL UNION
SELECT 111,1,2018,'OC','EXPENSE',-10000,-10000,'Recurring' UNION
SELECT 111,1,2018,'PA','INCOME',100000,100000,'Recurring' UNION
SELECT 111,1,2019,'icc','INCOME',500,NULL,NULL UNION
SELECT 111,1,2020,NULL,NULL,NULL,NULL,NULL
),Recurring AS (
SELECT tb.PROJECT_ID,tb.RELEASE_NO,tb.VALUE_TYPE,tb.VAL_DES,MIN([YEAR]) AS StartYear,MAX(COST) AS COST,MAX(tb.RUN_TATE) AS RUN_TATE
FROM tb WHERE FREQUENCY='Recurring'
GROUP BY tb.PROJECT_ID,tb.RELEASE_NO,tb.VALUE_TYPE,tb.VAL_DES
)
SELECT * FROM tb union
SELECT r.PROJECT_ID,r.RELEASE_NO,n.number AS [YEAR],r.VALUE_TYPE,r.VAL_DES,r.COST,r.RUN_TATE,NULL AS FREQUENCY FROM
Recurring AS r
OUTER APPLY (
SELECT sv.number FROM master.dbo.spt_values AS sv WHERE sv.type='P' AND sv.number BETWEEN r.StartYear+1 AND #EndYear
)n
PROJECT_ID RELEASE_NO YEAR VALUE_TYPE VAL_DES COST RUN_TATE FREQUENCY
----------- ----------- ----------- ---------- ------- ----------- ----------- ---------
111 1 2016 IR INCOME 10000 NULL NULL
111 1 2016 IT EXPENSE 0 NULL NULL
111 1 2016 OC EXPENSE -200000 NULL NULL
111 1 2016 Vendor EXPENSE -5000 NULL NULL
111 1 2017 BC INCOME 200000 NULL NULL
111 1 2017 ITA INCOME 5000 5000 Recurring
111 1 2017 OC EXPENSE -200000 NULL NULL
111 1 2018 ITA INCOME 5000 5000 NULL
111 1 2018 OC EXPENSE -10000 -10000 Recurring
111 1 2018 PA INCOME 100000 100000 Recurring
111 1 2019 icc INCOME 500 NULL NULL
111 1 2019 ITA INCOME 5000 5000 NULL
111 1 2019 OC EXPENSE -10000 -10000 NULL
111 1 2019 PA INCOME 100000 100000 NULL
111 1 2020 NULL NULL NULL NULL NULL
111 1 2020 ITA INCOME 5000 5000 NULL
111 1 2020 OC EXPENSE -10000 -10000 NULL
111 1 2020 PA INCOME 100000 100000 NULL