Pivot Dynamic Data in Oracle - oracle

I have rollup output of month-wise average sales of products in a quarter as shown below:
Rollup output:
Product Month Sales
------------------------------
Product1 MAY 101.27
Product2 MAY 5.47
Product1 JUN 1481.19
Product2 JUN 84.95
ALL QTR 836.44
I need final output in the following format:
Product1 Product2 AverageSales
May 101.27 1481.19 (null)
Jun 5.47 84.95 (null)
Jul 0 0 (null)
ALL (null) (null) 836.44
I tried to apply pivot on month but since month name is a dynamic value based on the quarter selected, I tried to pivot on the product:
select * from (rollup output)
PIVOT MIN(Sales) FOR Product IN ('Product1' AS Product1_sales, 'Product2' AS Product2_sales, 'ALL' AS Average Sales');
I received the following output:
MONTH Product1_sales Product2_sales Average Sales
MAY 5.47 (null) (null)
MAY (null) 101.27 (null)
JUN 84.95 (null) (null)
JUN (null) 1481.19 (null)
Qtr (null) (null) 836.44
However, I need data in the final format mentioned above. How can I achieve this?
Also, if data for a given month of the quarter is not available, I want to display its value as 0 (also shown in the final format above). How can I achieve that, considering that month name is dynamic?
Edit: I can pivot using product as well since I do not want xml output that comes out of dynamic pivot.

I'm not sure why it needs to be dynamic since the number of months is unlikely to change. Why not just:
select product
, nvl(jan,0) as jan
, nvl(feb,0) as feb
, nvl(mar,0) as mar
, nvl(apr,0) as apr
, nvl(may,0) as may
, nvl(jun,0) as jun
, nvl(jul,0) as jul
, nvl(aug,0) as aug
, nvl(sep,0) as sep
, nvl(oct,0) as oct
, nvl(nov,0) as nov
, nvl(dec,0) as dec
from rollup_output
pivot (min(sales) for (month) in
( 'JAN' as jan, 'FEB' as feb, 'MAR' as mar, 'APR' as apr, 'MAY' as may, 'JUN' as jun
, 'JUL' as jul, 'AUG' as aug, 'SEP' as sep, 'OCT' as oct, 'NOV' as nov, 'DEC' as dec)
);
SQL Fiddle

Related

Using a 0 rather than skipping the group entirely if nothing is found

How can I use a 0 as a "placeholder" here?
=QUERY(Data!A1:G578, "select G, sum(C) where D='Income' group by G label sum(C) 'Total Income'")
So that
Month
Total Income
August 2021
$784.59
October 2021
$200.00
November 2021
$312.74
becomes
Month
Total Income
August 2021
$784.59
September 2021
$0.00
October 2021
$200.00
November 2021
$312.74
The quickest hacky fix would be just to have an entry of 0$ for September in the data somewhere, but I am wondering if there is a more ""professional"" way to do it

How would I add an artificial termination date to the termination date column based on two different dates for the same patient id

I need to figure out a query that will compare two EFFECTIVE dates for a given patient number with different HMOs and determine which is the later date of the two and then populate a TERMINATION date field for only the older of the two effective dates with the last day of the previous month of the newer effective date of the two. This needs to be done across multiple patient, HMO, effective date combinations in a table.
SELECT * FROM tablename
The output is this:
HMO PATIENT EFFECTIVE TERMINATION
16 221135 01-APR-18
18 221135 01-OCT-17
12 251181 01-SEP-16
16 251181 01-MAR-15
12 271126 01-MAR-15
16 271126 01-DEC-16
12 291141 01-DEC-16
16 291141 01-FEB-19
12 391134 09-MAY-13
16 391134 01-APR-18
What I am trying to do via a query or queries is this:
HMO PATIENT EFFECTIVE TERMINATION
16 221235 01-APR-18
18 221235 01-OCT-17 3/31/2018
12 251381 01-SEP-16
16 251381 01-MAR-15 8/31/2016
12 2711126 01-MAR-15 11/30/2016
16 2711126 01-DEC-16
12 292241 01-DEC-16 1/31/2019
16 292241 01-FEB-19
12 391534 09-MAY-13 31-MAR-19
16 391534 01-APR-18
I've tried using a case statement but it is unsurprisingly creating four rows per patient, hmo combo and populating two of the rows with dates and leaving two blank:
SELECT DISTINCT
S.HMO
,S.PATIENT
,S.EFFECTIVE
,CASE WHEN S.EFFECTIVE > E.EFFECTIVE THEN LAST_DAY(ADD_MONTHS(S.EFFECTIVE, -1))
WHEN S.EFFECTIVE < E.EFFECTIVE THEN LAST_DAY(ADD_MONTHS(E.EFFECTIVE, -1))
ELSE NULL END AS TERMINATION
FROM tablename S INNER JOIN tablename E ON S.PATIENT=E.PATIENT
WHERE S.PATIENT =221135
Any ideas or advice would be welcome.
With sample data you posted:
SQL> select * from tablename order by patient, effective;
HMO PATIENT EFFECTIVE TERMINATIO
---------- ---------- ---------- ----------
18 221135 10/01/2017
16 221135 04/01/2018
16 251181 03/01/2015
12 251181 09/01/2016
12 271126 03/01/2015
16 271126 12/01/2016
6 rows selected.
such a MERGE might do:
SQL> merge into tablename a
2 using (select patient, max(effective) max_effective,
3 min(effective) min_effective
4 from tablename
5 group by patient
6 ) x
7 on (a.patient = x.patient)
8 when matched then update set
9 a.termination = x.max_effective - 1
10 where a.effective = x.min_effective;
3 rows merged.
Result is then
SQL> select * from tablename order by patient, effective;
HMO PATIENT EFFECTIVE TERMINATIO
---------- ---------- ---------- ----------
18 221135 10/01/2017 03/31/2018
16 221135 04/01/2018
16 251181 03/01/2015 08/31/2016
12 251181 09/01/2016
12 271126 03/01/2015 11/30/2016
16 271126 12/01/2016
6 rows selected.
SQL>

How to store multiple values in a variable to be used in a case statement

I am having this issue and any help in this regard will greatly be appreciated.
I have Oracle db and working with following business case:
An employee can work in a different job grades in his/her regular time hours or in overtime
Need to calculate employee’s hours w.r.t. different job grades and wage codes, because I have hours and job grades in different tables and the table which has job grades doesn’t have hours, instead time in and time out so after querying the db I get the following result.
Emp_ID
Wage Code
Job grade
Hours
Date
1
01
8
2021/06/07
1
02
P
2
2021/06/07
1
08
8
2021/06/08
1
01
6
2021/06/09
1
01
E
8
2021/06/09
1
01
8
2021/06/10
1
01
8
2021/06/11
1
02
9
2021/06/11
Now I get wrong hours when the employee works in different job grade(s).
To overcome this, I need to identify on which date employee worked in a different job grade do I can put case statement.
I used this logic.
Pick the date on which employee worked in different job grade and on that date do calculation of hours from table A
Other wise do calculation of hours from table B.
The problem is I can’t simply use variables because there could be multiple dates.
How can I achieve this? Can I use any other logic?
Thanks,
Here are my tables
TABLE A
Emp_ID
Wage_code
time_in
time_out
Job_grade
Date
01
8:00
16:00
2021-06-7
01
16:00
18:00
P
2021-06-7
01
8:00
16:00
2021-06-08
01
8:00
14:00
2021-06-09
01
14:00
16:00
E
2021-06-09
01
8:00
16:00
2021-06-10
01
8:00
16:00
2021-06-11
01
16:00
17:00
2021-06-11
This table doesn't store wage_codes. empty job_grade means employee has worked in the same job grade
TABLE B
Emp_ID
Wage_code
Hours
Date
01
1
8
2021-06-7
01
2
2
2021-06-7
01
8
8
2021-06-08
01
1
8
2021-06-09
01
1
8
2021-06-10
01
1
8
2021-06-11
01
2
2
2021-06-11
This table stores wage_codes but no job grade change, just a regular one and hours for each wage_code (1=regular,2=overtime,8=vacation etc..)
my query
select
A.emp_id,
A.job_grade,
B.Wage_code,
B.Date,
case
when A.job_grade ='' then B.Hours
else
to_char(A.time_in - A.time_out) *(24),'fm99.90')
end "Hours"
from A
left join B on A.emp_id=B.emp_id and A.Date=B.Date
With this query I get wrong hours when employee has worked in a different job grade. Because the condition in case statement checks if job grade is empty then calculate hours from Table B. Now e.g. on 06/07, employee has worked in a normal grade as well as in a different job grade.
How can I identify the date on which employee has worked in a different job grade so I can combine it with the job_grade condition in case statement and calculate hours accurately.
Many thanks for your support!!

Grabbing all rows from a database that have specific column values in laravel

I am dealing with a table that has a bunch of short names, ex.
some_id
long_name
short_name
94
March
mar
19
April
apr
0
June
jun
2
September
Sep
I want to grab only a few supported short names, ex. mar, sep, jun.
How would I go about doing it in laravel?
Currently I have something like this:
$this->result = DB::table('table_above')->get();
But this just grabs every table. I was thinking of adding the where command, but not sure how to check for multiple values.
$this->result = DB::table('table_above')->where('short_name', [somehow say either mar, sep, jun])->get();
At the end I'd like an array that holds a dictionary of rows (i.e $result) with the supported short names (i.e here mar, june, sept).
Try this query
DB :: table ('table_above')->whereIn('short_name', ['mar', 'sep'])->get()

oracle query to convert number format to date format or vice versa

In DB, date is stored in number format (Mon Jul 07 14:41:40 IST 2014
is stored as 1404724300383), I need a query to convert number to date to compare with the sysdate, or from sysdate to number format. How can we convert the date to number or vice versa?
Assume the number is a sequencial one based on specific rule. You need to know the rule first.
Get the rule
a) 07 July 2014 = 1404724300383; 07 July 2013 = ? (assume 1404700000000)
b) Assume value 0 mapping to one day, Day1
c) two formulas 1404724300383 = (07 July 2014 - Day1) * RULE; 1404700000000 = (07 July 2013 - Day1)*Rule;
Then, Rule = 24300383/365 and Day 1 = 1 Jan 1900 + 41285/(1404724300383/1404700000000*41460/((1404724300383/1404700000000)-1))
where 41825 is the days between 07 July 2014 and 1 Jan 1900)
41460 is the days between 07 July 2013 and 1 Jan 1900)
Use the Rule and Day1 to get what you need
select Day1 + [query column]/Rule from Your_Table;

Resources