join two PIVOT table - sql

I have this query
With
NoOfOrder as
(
SELECT Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec,Jan,Feb,Mar
FROM
(
select LEFT(datename(month,InvoiceDate),3) mon,InvoiceNo as InvoiceNo
from tbl_InvoiceMain ,tbl_OrderMain,tbl_CompanyMaster
where tbl_InvoiceMain.OrderID = tbl_OrderMain.OrderID
and (CAST(tbl_InvoiceMain.InvoiceDate AS date) BETWEEN tbl_CompanyMaster.YearStart AND tbl_CompanyMaster.YearEnd)
) P
PIVOT (count(InvoiceNo)for mon in (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)) PV
),
OnTime as
(
SELECT Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec,Jan,Feb,Mar
FROM
(
select LEFT(datename(month,InvoiceDate),3) mon,InvoiceNo as InvoiceNo
from tbl_InvoiceMain ,tbl_OrderMain,tbl_CompanyMaster
where tbl_InvoiceMain.OrderID = tbl_OrderMain.OrderID
and (CAST(tbl_InvoiceMain.InvoiceDate AS date) BETWEEN tbl_CompanyMaster.YearStart AND tbl_CompanyMaster.YearEnd)
and CAST(tbl_InvoiceMain.InvoiceDate AS date) <= CAST(tbl_OrderMain.ScheduledDispatchDate AS date)
) P
PIVOT (count(InvoiceNo)for mon in (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)) PV
)
Select * From NoOfOrder
union all
Select * From OnTime
It gives this result:
Apr May Jun Jul Aug Sep Oct Nov Dec Jan Feb Mar
18 35 39 52 32 47 47 22 14 0 0 0
9 10 16 22 6 11 19 10 5 0 0 0
Here is my expected result
Apr May Jun Jul Aug Sep Oct Nov Dec Jan Feb Mar
NoOfOrder 18 35 39 52 32 47 47 22 14 0 0 0
OnTimeDelivered 9 10 16 22 6 11 19 10 5 0 0 0
DeliverPerformance% 50.00 28.57 41.03 42.31 18.75 23.40 40.43 45.45 35.71 0.00 0.00 0.00
The formula for DeliverPerformance is:
DeliverPerformance% = (OnTimeDelivered/NoOfOrder) X 100
How do I achieve this result on the next row?
for reference you check my question in good format
enter link description here

My immediate suggestion is to combine everything first prior to pivoting the results.
Your first query might look like this:
SELECT
LEFT(datename(month, InvoiceDate), 3) InvMon,
SUM(1) AS NoOfOrder,
SUM(CASE WHEN CAST(tbl_InvoiceMain.InvoiceDate AS date) <= CAST(tbl_OrderMain.ScheduledDispatchDate AS date) THEN 1 ELSE 0 END) OnTimeDelivered
FROM tbl_InvoiceMain, tbl_OrderMain, tbl_CompanyMaster
WHERE tbl_InvoiceMain.OrderID = tbl_OrderMain.OrderID
AND (CAST(tbl_InvoiceMain.InvoiceDate AS date) BETWEEN tbl_CompanyMaster.YearStart AND tbl_CompanyMaster.YearEnd)
GROUP BY LEFT(datename(month, InvoiceDate), 3)
Note that I'm always counting every invoice record and optionally counting the "on time" invoices with that CASE statement and the respective SUM functions.
My next thought is to put that query in a CTE and then the statement that uses that CTE will do the additional calculation like so:
SELECT InvMon, NoOfOrder, OnTimeDelivered, ((OnTimeDelivered / NoOfOrder) * 100) DeliverPerformance ...
And finally, that's what I pivot.

Related

Select row with most recent date per location and increment recent date by 1 for each row by location using MariaDB

I have a table of location which has 'Date column'. I have to find recent date by each group of locationID for e.g. locationID 1 has most recent date '31 May 2022'. After finding recent date from the group of locationID I have to add 14 days in that recent date and store it in NewDate column. and add + 1 in that new date for other row for that group of locationID.
My table is:
id locationID Date NewDate
1 1 31 May 2022
2 1 16 May 2022
3 1 28 Apr 2021
4 2 29 Mar 2022
5 2 22 Feb 2022
6 3 14 Jun 2022
7 3 27 Oct 2021
8 4 01 Feb 2022
9 4 04 May 2022
10 4 14 Jun 2021
11 5 01 Jun 2022
12 5 29 May 2022
13 5 20 Sep 2022
14 5 11 Aug 2022
15 5 03 Aug 2022
Answer should be as below:
For e.g. for locationID = 1
id locationID Date NewDate
1 1 31 May 2022 14 Jun 2022 // Recent Date + 14 Days - 31 May + 14 Days
2 1 16 May 2022 15 Jun 2022 // Recent Date + 15 Days - 31 May + 15 Days
3 1 28 Apr 2021 16 Jun 2022 // Recent Date + 16 Days - 31 May + 16 Days
I have come across few similar post and found recent date like this:
SELECT L.*
FROM Locations L
INNER JOIN
(SELECT locationID, MAX(Date) AS MAXdate
FROM Locations
GROUP BY locationID) groupedL
ON L.locationID = groupedL.locationID
AND L.Date = groupedL.MAXdate
using above code I am able to find recent date per location but how do I add and increment required days and store it to NewDate column ? I am new to MariaDB, please suggest similar post link, any reference documents or blogs. Should I make some function to perform this logic and call the function to store required dates in NewDate column? I am not sure please suggest. Thank you.
RESULT SHOULD LOOK LIKE BELOW:
id locationID Date NewDate
1 1 31 May 2022 14 Jun 2022 // Recent Date for locationid 1 + 14 Days - 31 May + 14 Days
2 1 16 May 2022 15 Jun 2022 // Recent Date for locationid 1 + 15 Days - 31 May + 15 Days
3 1 28 Apr 2021 16 Jun 2022 // Recent Date for locationid 1 + 16 Days - 31 May + 16 Days
4 2 29 Mar 2022 12 APR 2022 // Recent Date for locationid 2 + 14 Days
5 2 22 Feb 2022 13 APR 2022 // Recent Date for locationid 2 + 15 Days
6 3 14 Jun 2022 28 JUN 2022 // Recent Date for locationid 3 + 14 Days
7 3 27 Oct 2021 29 JUN 2022 // Recent Date for locationid 3 + 15 Days
8 4 01 Feb 2022 18 MAY 2022 // Recent Date for locationid 4 + 14 Days
9 4 04 May 2022 19 MAY 2022 // Recent Date for locationid 4 + 15 Days
10 4 14 Jun 2021 20 MAY 2022 // Recent Date for locationid 4 + 16 Days
11 5 01 Jun 2022 04 OCT 2022 // Recent Date for locationid 5 + 14 Days
12 5 29 May 2022 05 OCT 2022 // Recent Date for locationid 5 + 15 Days
13 5 20 Sep 2022 06 OCT 2022 // Recent Date for locationid 5 + 16 Days
14 5 11 Aug 2022 07 OCT 2022 // Recent Date for locationid 5 + 17 Days
15 5 03 Aug 2022 08 OCT 2022 // Recent Date for locationid 5 + 18 Days
You can use a cte:
with cte as (
select l1.*, l2.m, (select sum(l4.id < l1.id and l4.locationid = l1.locationid) from locations l4) inc from locations l1
join (select l3.locationid, max(l3.dt) m from locations l3 group by l3.locationid) l2 on l1.locationid = l2.locationid
)
select c.id, c.locationid, c.dt, c.m + interval 14 + c.inc day from cte c
You could use analytic window functions and update the original table by joining to a sub-query (works for MariaDB):
update t
join (
select Id,
Date_Add(First_Value(date) over(partition by locationId order by date desc),
interval (13 + row_number() over(partition by locationId order by date desc)) day
) NewDate
from t
)nd on t.id = nd.id
set t.Newdate = nd.NewDate;
See DB<>Fiddle example

Pivot table times by a table

I have some code for a pivot table but I also want to times (x) it buy another table if it full into the criteria.
select *
from
(SELECT
year(dteOccupiedDate) as [year],
moveincharge as type ,
left(datename(month,dteOccupiedDate),3)as [month],
MoveInCharge
FROM dav.Gainshare where strTenancyType = 'LTO' and dteOccupiedDate between '2020-04-01' and '2021-03-31' and moveincharge is not null
) as s
PIVOT
(
count(moveincharge)
FOR [month] IN (jan, feb, mar, apr,
may, jun, jul, aug, sep, oct, nov, dec)
)AS pvt
order by year
this code shows
year type jan feb mar apr may jun jul aug sep oct nov dec
2020 Single 0 0 0 5 1 4 12 12 6 0 0 0
2020 Family 0 0 0 5 1 4 12 12 6 0 0 0
2020 Early-leave 0 0 0 5 1 4 12 12 6 0 0 0
2020 Re-house 0 0 0 5 1 4 12 12 6 0 0 0
they are 4 different moveincharge types when it fallin that type I want it X times by the
single (150)
family (200)
rehouse (130)
early leave (140)
I can also make these into a table if that make it better.
I want to see this
year type jan feb mar apr may jun jul aug sep oct nov dec
2020 Single 0 0 0 750 150 600 1800 1800 900 0 0 0
fo example Type Single for July is 12 x 150 because single is worth 150 each and there are 12 in that month
I much prefer conditional aggregation over the bespoke pivot syntax. This is easily accomplished with a join:
select year(gs.dteOccupiedDate) as [year],
sum(case when month(gs.dteOccupiedDate) = 1 then v.charge else 0 end) as jan,
sum(case when month(gs.dteOccupiedDate) = 2 then v.charge else 0 end) as feb,
. . .
from dav.Gainshare gs join
(values ('single', 150), ('family', 200), . . .
) v(moveincharge, charge)
on gs.movincharge = v.ovincharge
where gs.strTenancyType = 'LTO' and
gs.dteOccupiedDate between '2020-04-01' and '2021-03-31' and
gs.moveincharge is not null
group by year(gs.dteOccupiedDate);
Note: This will return two rows -- one for 2020 and one for 2021. That is what your query does. You might want to remove the group by and the year from the select.

Postgres query for annual sales report by rep. grouped by month

I would like to create an annual sales report table by sales rep, showing all the twelve month. The data I have is more or less like in this example:
id | rep | date | price
----------------------------
1 1 2017-01-01 20
2 1 2017-01-20 44
3 2 2017-02-18 13
4 2 2017-03-08 12
5 2 2017-04-01 88
6 2 2017-09-05 67
7 3 2017-01-31 10
8 3 2017-06-01 74
The result I need would be like this:
Rep Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
----------------------------------------------------
1 64 0 0 0 0 0 0 0 0 0 0 0
2 0 13 12 88 0 0 0 0 67 0 0 0
3 10 0 0 0 0 74 0 0 0 0 0 0
What would be the most efficient way to write this query?
One way:
select rep,
sum(case when extract('month' from date) = 1 then price else 0 end ) as Jan,
sum(case when extract('month' from date) = 2 then price else 0 end ) as Feb
-- another months here
from t
group by rep
One way is to use windowed functions with FILTER:
SELECT DISTINCT
"rep",
COALESCE(SUM(price) FILTER (WHERE extract('month' from "date") = 1) OVER(PARTITION BY "rep"),0) AS Jan,
COALESCE(SUM(price) FILTER (WHERE extract('month' from "date") = 2) OVER(PARTITION BY "rep"),0) AS Feb
--....
FROM ta;
Rextester Demo
Warning!
You probably want to partition by YEAR too to avoid summing JAN 2017 and JAN 2018.

Converting Row Into a Column based on Month

I have following input:
JAN_OLD FEB_OLD MAR_OLD APR_OLD MAY_OLD JUNE_OLD JAN_NEW FEB_NEW MAR_NEW APR_NEW MAY_NEW JUNE_NEW
10 11 12 13 14 15 20 21 22 23 24 25
Disired result set is as below:
JAN New OLD
FEB 20 10
MAR 21 11
APR 22 12
MAY 23 13
JUN 24 14
Can someone suggest how to achieve this?
Multiple Union All or single Cross Apply
SELECT months,old,new
FROM Your_table
CROSS apply (VALUES(jan_old,jan_new,'Jan'),
(FEB_OLD,FEB_new,'Feb'),
(MAR_OLD,MAR_new,'Mar'),
(APR_OLD,APR_new,'Apr'),
(MAY_OLD,MAY_new,'may'),
(JUNE_OLD,JUNE_new,'Jun'))
cs (old, new, months)
If you are not sure about the no. of columns then you may have to use Dynamic sql

Crosstab with static column

How can I make a static column/row in crosstab? See example below; can I have a fixed jan, feb, march, ... columns instead of it generating dynamically?
location jan feb mar apr may jun jul aug sep oct nov dec
london 500 62 200 50 0 60 100 46 89 200 150 210
paris 50 26 20 500 50 70 40 200 0 40 250 50
I want the column (jan, feb, mar, apr, ...) to always show up regardless of their measures zero or have values. Like they are fixed.
Here is the query I'm using:
select sum("AMOUNT"), "REQUESTDATE","description"
from(
SELECT SUM(e.AMOUNT)"AMOUNT",TO_CHAR(REQUESTDATE,'MM')"REQUESTDATE", CA.DESCR "description"
FROM PC_PAYMENTTRXNLOG PC,GLB_TYPE ca, PC_ESERVICEINQUIRY e
where PC.ESERVICE_ID = E.ID
AND trunc(REQUESTDATE) between trunc(to_date('2012-01-01','yyyy-mm-dd')) and trunc(to_date('2012-06-30','yyyy-mm-dd'))
GROUP BY TO_CHAR(REQUESTDATE,'MM'),CA.DESCR
)
group by "REQUESTDATE","description"
and the output
SUM("amount") Requestdate Description
2550405 04 A
2550405 04 B
23893281 05 C
614977 06 A
614977 06 E
2550405 04 C
now after updated the query to be
select sum("AMOUNT"), month,"description"
from(
SELECT SUM(e.AMOUNT)"AMOUNT",TO_CHAR(REQUESTDATE,'MM')"REQUESTDATE", CA.DESCR "description"
FROM PC_PAYMENTTRXNLOG PC,GLB_TYPE ca, PC_ESERVICEINQUIRY e
where PC.ESERVICE_ID = E.ID
AND trunc(REQUESTDATE) between trunc(to_date('2012-01-01','yyyy-mm-dd')) and trunc(to_date('2012-06-30','yyyy-mm-dd'))
GROUP BY TO_CHAR(REQUESTDATE,'MM'),CA.DESCR
)
full outer join (select to_char(date '1970-01-01'
+ numtoyminterval(level - 1, 'month'), 'mm') as month
from dual
connect by level <= 12) on month="REQUESTDATE"
group by month,"description"
when run the query run it displaying all the months regardless of their measures zero or have values.
BUT now the output is like that
location jan feb mar apr may jun jul aug sep oct nov dec
london 500 62 200 50 0 60 100 46 89 200 150 210
paris 50 26 20 500 50 70 40 200 0 40 250 50
null 0 0 0 0 0 0 0 0 0 0 0 0
how i can restrict/hide the last null row?
have not tested it.. but try something like this
select sum("AMOUNT"), month,"description"
from(SELECT SUM(e.AMOUNT)"AMOUNT",TO_CHAR(REQUESTDATE,'MM')"REQUESTDATE", CA.DESCR "description"
FROM PC_PAYMENTTRXNLOG PC,GLB_TYPE ca, PC_ESERVICEINQUIRY e
where PC.ESERVICE_ID = E.ID
AND trunc(REQUESTDATE) between trunc(to_date('2012-01-01','yyyy-mm-dd')) and trunc(to_date('2012-06-30','yyyy-mm-dd'))
GROUP BY TO_CHAR(REQUESTDATE,'MM'),CA.DESCR
)
full outer join (select to_char(date '1970-01-01'
+ numtoyminterval(level - 1, 'month'), 'mm') as month
from dual
connect by level <= 12) on month="REQUESTDATE"
group by month,"description"
click here for SQL Fiddle demo to generate 1 to 12 in Oracle
Once you have generated this.. full outer join Your main query with this series query and take month from series query as I did in main query.
Using this query you will get all the data for all months with null values in measure.
For Description column - iReport set property's isRemoveLineWhenBlank and isBlankWhenNull to True, This will remove the null value being printed in iReport
For Measure use Print when expression in such a way, when ever description is null then return false. So this will prevent the value 0 being printed in iReport.