SQL - YTD and MTD in rows instead of columns - sql

Let's say I have this table:
FiscalPeriod
FiscalMonth
FiscalYear
Division
L4
L5
L6
L7
AMT_LEGAL_USD
01-2022
1
2022
A
NOP
OP
GM
NS
1000
02-2022
2
2022
A
NOP
OP
GM
NS
2000
03-2022
3
2022
A
NOP
OP
GM
NS
2000
01-2022
1
2022
B
NOP
OP
GM
NS
1000
02-2022
2
2022
B
NOP
OP
GM
NS
3000
03-2022
3
2022
B
NOP
OP
GM
NS
5000
01-2022
1
2022
C
NOP
OP
GM
NS
1000
02-2022
2
2022
C
NOP
OP
GM
NS
1000
03-2022
3
2022
C
NOP
OP
GM
NS
1000
I'm trying to build a table that queries this one and calculates MTD (month to date) and YTD (Year to Date): for each Division, caculate the MTD and YTD based on FiscalMonth and FiscalYear columns, for each of my KPIs (columns L4 to L7)
I have the following query:
SELECT
ec.FiscalPeriod,
ec.FiscalMonth,
ec.FiscalYear,
ec.Divison,
sum(CASE WHEN L7 = 'NS' then EC.AMT_LEGAL_USD else 0 end) as NS_MTD,
sum(NS_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Divison ORDER BY ec.FiscalPeriod) AS NS_YTD,
sum(CASE WHEN L6 = 'GM' then EC.AMT_LEGAL_USD else 0 end) as GM_MTD,
sum(GM_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Divison ORDER BY ec.FiscalPeriod) AS GM_YTD,
sum(CASE WHEN L5 = 'OP' then EC.AMT_LEGAL_USD else 0 end) as OP_MTD,
sum(OP_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Divison ORDER BY ec.FiscalPeriod) AS OP_YTD,
sum(CASE WHEN L4 = 'NOP' then EC.AMT_LEGAL_USD else 0 end) as NOP_MTD,
sum(NOP_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Divison ORDER BY ec.FiscalPeriod) AS NOP_YTD,
from my table ec
group by 1,2,3,4
having Net_Sales_MTD != 0 and GM_MTD != 0 and OP_MTD != 0 and NOP_MTD != 0
order by 1 asc;
That will return me something like:
FiscalPeriod
FiscalMonth
FiscalYear
Division
NS_MTD
NS_YTD
GM_MTD
GM_YTD
OP_MTD
OP_YTD
NOP_MTD
NOP_YTD
01-2022
1
2022
A
1000
1000
1000
1000
1000
1000
1000
1000
02-2022
2
2022
A
2000
3000
2000
3000
2000
3000
2000
3000
03-2022
3
2022
A
2000
5000
2000
5000
2000
5000
2000
5000
01-2022
1
2022
B
1000
1000
1000
1000
1000
1000
1000
1000
02-2022
2
2022
B
3000
4000
3000
4000
3000
4000
3000
4000
03-2022
3
2022
B
5000
9000
5000
9000
5000
9000
5000
9000
01-2022
1
2022
C
1000
1000
1000
2000
1000
3000
1000
1000
02-2022
2
2022
C
1000
2000
1000
2000
1000
2000
1000
2000
03-2022
3
2022
C
1000
3000
1000
3000
1000
3000
1000
3000
I would like to get an output that would look like:
FiscalPeriod
FiscalMonth
FiscalYear
Division
Period
NOP
OP
GM
NS
01-2022
1
2022
A
MTD
1000
1000
1000
1000
01-2022
1
2022
A
YTD
1000
1000
1000
1000
02-2022
2
2022
A
MTD
2000
2000
2000
2000
02-2022
2
2022
A
YTD
3000
3000
3000
3000
03-2022
3
2022
A
MTD
2000
2000
2000
2000
03-2022
3
2022
A
YTD
5000
5000
5000
5000
01-2022
1
2022
B
MTD
1000
1000
1000
1000
01-2022
1
2022
B
YTD
1000
1000
1000
1000
02-2022
2
2022
B
MTD
3000
3000
3000
3000
02-2022
2
2022
B
YTD
4000
4000
4000
4000
03-2022
3
2022
B
MTD
5000
5000
5000
5000
03-2022
3
2022
B
YTD
9000
9000
9000
9000
01-2022
1
2022
C
MTD
1000
1000
1000
1000
01-2022
1
2022
C
YTD
1000
1000
1000
1000
02-2022
2
2022
C
MTD
1000
1000
1000
1000
02-2022
2
2022
C
YTD
2000
2000
2000
2000
03-2022
3
2022
C
MTD
1000
1000
1000
1000
03-2022
3
2022
C
YTD
3000
3000
3000
3000
Any ideas on how this can be achivied? Hopefully that wasn't too confusing.
Appreciate any feedback and ideas on how to do this.

I think you'll need to do this in two steps:
Calculate MTD
Calculate YTD
Union All
Here is an example based on your data.
with mtd as (
SELECT
ec.FiscalPeriod,
ec.FiscalMonth,
ec.FiscalYear,
ec.Division,
'MTD' as Period,
sum(CASE WHEN L7 = 'NS' then EC.AMT_LEGAL_USD else 0 end) as NS_MTD,
sum(CASE WHEN L6 = 'GM' then EC.AMT_LEGAL_USD else 0 end) as GM_MTD,
sum(CASE WHEN L5 = 'OP' then EC.AMT_LEGAL_USD else 0 end) as OP_MTD,
sum(CASE WHEN L4 = 'NOP' then EC.AMT_LEGAL_USD else 0 end) as NOP_MTD
from data ec
group by 1,2,3,4
)
, ytd as (
SELECT
ec.FiscalPeriod,
ec.FiscalMonth,
ec.FiscalYear,
ec.Division,
'YTD' as Period,
sum(NS_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Division ORDER BY ec.FiscalPeriod) AS NS_YTD,
sum(GM_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Division ORDER BY ec.FiscalPeriod) AS GM_YTD,
sum(OP_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Division ORDER BY ec.FiscalPeriod) AS OP_YTD,
sum(NOP_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Division ORDER BY ec.FiscalPeriod) AS NOP_YTD
from mtd ec
group by 1,2,3,4, NS_MTD, gm_mtd, op_mtd, op_mtd, nop_mtd
)
select * from (
select * from mtd
union all
select * from ytd
) foo
order by fiscalyear, division, fiscalperiod, fiscalmonth, period

Related

Converting Weeknumber Fields into Rows

I have a table that is layed out as follows :
Code,Year, Wk1Val, Wk2Val, Wk3Val, Wk4Val etc to to Wk52Val.
Is there SQL to show the data as follows, without having to do 52 Case statements :
Code, Year, Week, Value
You can use UNPIVOT with REPLACE functions. Be sure to add all 52 week columns to the UNPIVOT IN portion of the query.
SELECT
u.Code,
u.Year,
REPLACE(REPLACE(u.Weeks, 'Wk', ''), 'Val', '') AS Weeks,
u.Value
FROM test
UNPIVOT
(
Value FOR Weeks IN (Wk1Val, Wk2Val, Wk3Val, Wk4Val, Wk52Val)
) AS u;
Fiddle here.
Input:
Code
Year
Wk1Val
Wk2Val
Wk3Val
Wk4Val
Wk52Val
1
2022
5000
15000
9000
4000
1000
2
2022
900
3200
7000
8500
9500
3
2022
3500
7800
10000
6200
5600
Output:
Code
Year
Weeks
Value
1
2022
1
5000
1
2022
2
15000
1
2022
3
9000
1
2022
4
4000
1
2022
52
1000
2
2022
1
900
2
2022
2
3200
2
2022
3
7000
2
2022
4
8500
2
2022
52
9500
3
2022
1
3500
3
2022
2
7800
3
2022
3
10000
3
2022
4
6200
3
2022
52
5600

Need to find count of profit and loss and no data using select subquery

I have the following table
Years Months Credit Debit ProfitandLoss Symbol
2019 Jan 10000 2000 1000 P
2019 Aug 8000 1000 -10922 L
2019 May 5000 3000 2000 P
2020 Feb 10000 5000 800 P
2020 Apr 1000 6000 0 N
2020 Oct 2000 1000 2000 P
2021 Jan 6000 8000 -600 L
2021 Mar 2000 3000 1400 P
2021 Nov 2000 2000 0 N
Here I need to calculate total credit, total debit, total profit and loss and total count of profit, total count of loss, total count of nothing in one result table.
I have tried this but cannot get CountOfProfit, CountOfLoss and CountNothing according to years.
select Years,
SUM(credit) as [Total Credit],
SUM(debit) as totaldebit,
COUNT(Symbol) as totalcredit,
(select COUNT(Symbol) from Yearly where Symbol='P') as CountofProfit,
(select COUNT(Symbol) from Yearly where Symbol='L') as CountofLoss,
(select COUNT(Symbol) from Yearly where Symbol='N')as CountNothing
from Yearly
group by Years
My result table should be like
Years TotalCredit TotalDebit TotalProfitandLoss CountOfProfit CountofLoss CountofNothing
2019 23000 7000 -7022 2 1 0
2020 13000 12000 2800 2 0 1
2021 10000 13000 800 1 1 1
You need use conditional aggregation. This is achieved with a CASE expression:
SELECT Years,
SUM(Credit) AS TotalCredit,
SUM(Debit) AS TotalDebit,
SUM(ProfitandLoss) AS TotalProfitAndLoss,
COUNT(CASE Symbol WHEN 'P' THEN 1 END) AS Profits,
COUNT(CASE Symbol WHEN 'L' THEN 1 END) AS Losses,
COUNT(CASE Symbol WHEN 'N' THEN 1 END) AS Nothings
FROM (VALUES(2019,'Jan',10000,2000, 1000 ,'P'),
(2019,'Aug',8000 ,1000,-10922,'L'),
(2019,'May',5000 ,3000, 2000 ,'P'),
(2020,'Feb',10000,5000, 800 ,'P'),
(2020,'Apr',1000 ,6000, 0 ,'N'),
(2020,'Oct',2000 ,1000, 2000 ,'P'),
(2021,'Jan',6000 ,8000, -600 ,'L'),
(2021,'Mar',2000 ,3000, 1400 ,'P'),
(2021,'Nov',2000 ,2000, 0 ,'N'))V(Years,Months,Credit,Debit,ProfitandLoss,Symbol)
GROUP BY Years
ORDER BY Years;

Merging Two Tables and Calculating Amount (Currency Conversion)

I have table which contains the currency exchange rates and another one with converted amounts.
Currency Table
This table will have the daily rates of the currency. For the ease of mapping I have only included rates for one date.
Branch Code Rate Date
A 0 1 30/10/2019
A 1 200 30/10/2019
A 2 300 30/10/2019
B 0 1 30/10/2019
B 1 10 30/10/2019
B 2 30 30/10/2019
Converted Amounts Table
This table will have the daily exchange details. For the ease of mapping I have only included transactions for one date.
Branch Code Amt Date
A 0 1000 30/10/2019
A 1 2000 30/10/2019
A 2 3000 30/10/2019
A 2 4000 30/10/2019
A 2 5000 30/10/2019
A 0 6000 30/10/2019
B 0 7000 30/10/2019
B 0 8000 30/10/2019
B 0 9000 30/10/2019
B 2 10000 30/10/2019
Resultant Table
Branch Code Date Amt Branch Code Rate Total
A 0 30/10/2019 1000 A 0 1 1000
A 1 30/10/2019 2000 A 1 200 400000
A 2 30/10/2019 3000 A 2 300 900000
A 2 30/10/2019 4000 A 2 300 1200000
A 2 30/10/2019 5000 A 2 300 1500000
A 0 30/10/2019 6000 A 1 1 6000
B 0 30/10/2019 7000 A 1 200 1400000
B 0 30/10/2019 8000 A 1 200 1600000
B 0 30/10/2019 9000 A 1 200 1800000
B 2 30/10/2019 10000 A 2 300 3000000
I could only get the following resultant table.
Branch Code Date Amt Branch Code Rate Total
A 0 30/10/2019 1000 A 0 1 1000
A 1 30/10/2019 2000 A 1 200 400000
A 2 30/10/2019 3000 A 2 300 900000
A 2 30/10/2019 4000 A 2 300 1200000
A 2 30/10/2019 5000 A 2 300 1500000
A 0 30/10/2019 6000 A 1 1 6000
B 0 30/10/2019 7000 A 1 1 7000
B 0 30/10/2019 8000 A 1 1 8000
B 0 30/10/2019 9000 A 1 1 9000
B 2 30/10/2019 10000 A 2 300 3000000
Query I use.
SELECT
*
FROM
converted_amounts_table t1
LEFT OUTER JOIN (
SELECT
(
CASE WHEN code = '0'
AND branch = 'B' THEN '1' ELSE code END
) AS new_code,
branch,
date,
rate
FROM
currency_table
) t2 ON (
t1.date = t2.date
AND t1.code = t2.new_code
)
WHERE
t1.date >= '01-Jan-2019'
AND t1.date <= '30-Sep-2019'
I was able to get the resultant table.
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=4d5401320bda5ad736070541d55d1d04
SELECT
t1.branch,
t1.date2,
t1.code,
t2.code,
t2.new_code,
t2.rate,
t1.amt,
t1.amt * t2.rate AS Total
FROM
converted_amounts_table t1
LEFT OUTER JOIN (
SELECT
(CASE WHEN code = 1 THEN 0 ELSE code END) AS new_code,
branch,
date1,
code,
rate
FROM
currency_table
WHERE
branch = 'A'
) t2 ON (
t1.date2 = t2.date1
AND t1.code IN (t2.new_code, t2.code)
)
WHERE
t1.date2 = '30 - Oct - 2019'
AND (
t1.branch, t1.code, t2.code, t2.new_code,
t2.rate
) NOT IN (
('B', 0, 0, 0, 1),
('A', 0, 1, 0, 200)
)

Conditional Logic within SUM

I'm currently combining two tables through a UNION ALL query and performing SUM and GROUP BY operations on the result. Everything is working as expected, but I have a unique requirement which I can't seem to figure out how to implement.
My aim is to write SQL that says "when DEV_AGE column is >= 12 set the REVENUE value to what it would be if this column was 12". I provide the code below as I know this description can be a bit confusing:
REVENUE table:
ACC_YR DEV_AGE STATE REVENUE LOSS
2012 3 MA 4000 0
2012 6 MA 8000 0
2012 9 MA 12000 0
2012 12 MA 16000 0
LOSS table:
ACC_YR DEV_AGE STATE REVENUE LOSS
2012 3 MA 0 2000
2012 6 MA 0 7000
2012 9 MA 0 9000
2012 12 MA 0 10000
2012 15 MA 0 14000
2012 18 MA 0 14000
2012 21 MA 0 14000
2012 24 MA 0 15000
2012 27 MA 0 17000
Table after UNION ALL, GROUP BY, SUM:
ACC_YR DEV_AGE STATE REVENUE LOSS
2012 3 MA 4000 2000
2012 6 MA 8000 7000
2012 9 MA 12000 9000
2012 12 MA 16000 10000
2012 15 MA 0 14000
2012 18 MA 0 14000
2012 21 MA 0 14000
2012 24 MA 0 15000
2012 27 MA 0 17000
What I WANT to accomplish:
ACC_YR DEV_AGE STATE REVENUE LOSS
2012 3 MA 4000 2000
2012 6 MA 8000 7000
2012 9 MA 12000 9000
2012 12 MA 16000 10000
2012 15 MA 16000 14000
2012 18 MA 16000 14000
2012 21 MA 16000 14000
2012 24 MA 16000 15000
2012 27 MA 16000 17000
In other words, my REVENUE stops developing at a DEV_AGE of 12 (there are no rows in the REVENUE table beyond a DEV_AGE of 12), but I want every DEV_AGE beyond 12 to equal what the REVENUE was at 12 in the final table.
Here is an approach that uses window functions to calculate the revenue for age 12 and then logic to assign it:
select acc_yr, dev_age, state,
(case when dev_age > 12 then rev12 else revenue end) as revenue, loss
from (select l.acc_yr, l.dev_age, l.state, r.revenue, l.loss,
max(case when l.dev_age = 12 then r.revenue end) over (partition by l.acc_yr, l.state) as rev12
from loss l left join
revenue r
on l.acc_yr = r.acc_yr and l.dev_age = r.dev_age and l.state = dev.state
) lr;

Join Three tables with Sum of column in access query

I have Three tables as shown below..
I need output as shown in output table
for this i need to join three tables and order output in month order
tbl_MonthList
MonthID MonthList
1 January
2 February
3 March
4 April
5 May
6 June
7 July
8 August
9 September
10 October
11 November
12 December
tbl_Amount:
Month_id Amount_Received Customer_id
3 500 aaa
3 1000 bbb
4 700 jjj
5 300 aaa
5 400 jjj
5 500 ppp
7 1000 aaa
10 1500 bbb
12 700 jjj
tbl_Month_Target
MonthID MonthF_L
1 10000
2 150000
3 1000
4 50000
5 5000
6 3000
7 20000
8 12000
9 34000
10 85000
11 34000
12 45000
I need output as shown below
Month Total_amount MonthF_L
January 0 10000
February 0 150000
March 2000 1000
April 700 50000
May 1200 5000
June 0 3000
July 1000 20000
August 0 12000
September 0 34000
October 1500 85000
November 0 34000
December 700 45000
SELECT ML.MonthList AS Month,
Sum(A.Amount_Received) AS Total_amount,
First(MT.MonthF_L) AS MonthF_L
FROM (tbl_MonthList AS ML
INNER JOIN tbl_Month_Target AS MT ON ML.MonthID = MT.MonthID)
LEFT JOIN tbl_Amount AS A ON ML.MonthID = A.Month_id
GROUP BY ML.MonthList, ML.MonthID
ORDER BY ML.MonthID
Note: In MS Access, multiple joins must be explicitly nested within parentheses
Try this:
select ml.MonthList, sum(a.Amount_Received), mt.MonthF_L from tbl_MonthList ml
left join tbl_Month_Target mt on mt.MonthID = ml.MonthID
left join tbl_Amount a on ml.Month_id = ml.MonthID
group by ml.MonthList, mt.MonthF_L