Reputation: 109
I am a beginner in SQL and would like to group by date/num for joined data to create a new column. My data looks like the following after I pulled it:
select
items.A,
items.B,
items.C,
items.NUM,
items.E,
source.QTY,
dates.DATE
from original_metric source
inner join grocery items
on items.id = source.item_id
inner join day_dates dates
on dates.date_id = source.date_id;
A B C NUM E QTY DATE
Vegetable carrot John 1 Main 14 26-APR-11
Vegetable carrot John 1 Main 35 27-APR-11
Vegetable carrot John 1 Main 2 21-SEP-15
Vegetable carrot John 1 Main 11 23-APR-17
Vegetable carrot John 1 Main 25 22-MAY-17
Vegetable carrot John 1 Main 20 20-APR-18
Vegetable onion John 2 Extra 23 02-AUG-16
Vegetable onion John 2 Extra 32 07-AUG-16
Meat pork Jane 3 Main 10 02-AUG-16
Meat pork Jane 3 Main 60 19-JAN-17
Meat pork Jane 3 Main 12 25-DEC-17
What I would like it to look like:
A B C NUM E QTY DATE QTR WEEK_FILL CURRENT_FILL
Vegetable carrot John 1 Main 49 24-APR-11:30-APR-11 2011Q4 none 100%
Vegetable carrot John 1 Main 2 20-SEP-15:15-SEP-15 2015Q2 none 100%
Vegetable carrot John 1 Main 11 23-APR-17:29-APR-17 2017Q4 22.4% 73.4%
Vegetable carrot John 1 Main 25 21-MAY-17:27-MAY-17 2017Q4 51% 73.4%
Vegetable carrot John 1 Main 20 15-APR-18:21-APR-18 2018Q4 80% 80%
Vegetable onion John 2 Extra 55 31-JUL-16:07-AUG-16 2016Q1 none 100%
Meat pork Jane 3 Main 10 31-JUL-16:07-AUG-16 2016Q1 none 100%
Meat pork Jane 3 Main 60 15-JAN-17:21-JAN-17 2017Q3 none 100%
Meat pork Jane 3 Main 12 24-DEC-17:30-DEC-17 2017Q3 none 100%
I would like to group QTY by week by NUM. Then based on the DATE, show which QTR it belongs in.
Then, for WEEK_FILL I am trying to incorporate the following logic: QTY (in that week) divide by the sum (all QTY of the same quarter from the previous year) by NUM. If no previous year, go further back until there is a matching quarter. Else, if there are no prior years, then leave it as 'none'.
Then, for CURRENT_FILL, I am trying to incorporate a similar logic: sum(all QTY in that quarter) divide by the sum(all QTY in same quarter from the previous year) by NUM. If no previous year, go further back until there is a matching quarter. Else, if there are no prior years, then leave it as 100%.
(For reference, fiscal calendar Q1: JUN, JUL, AUG; Q2: SEP, OCT, NOV; Q3: DEC, JAN, FEB; Q4: MAR, APR, MAY)
Upvotes: 0
Views: 71
Reputation: 3906
Try this query
WITH dataCTE AS(
SELECT
q.*,
DENSE_RANK()OVER(PARTITION BY q.NUM,q.Q ORDER BY q.Y) Y_ORDER
FROM
(
SELECT
d.*,
EXTRACT(YEAR FROM DT) Y,
-- Q1: JUN, JUL, AUG; Q2: SEP, OCT, NOV; Q3: DEC, JAN, FEB; Q4: MAR, APR, MAY
DECODE(EXTRACT(MONTH FROM DT),6,1,7,1,8,1,9,2,10,2,11,2,12,3,1,3,2,3,3,4,4,4,5,4) Q
FROM TEST_DATA d
) q
)
SELECT
d.*,
Y||'Q'||Q QTR,
NVL(TO_CHAR(100*d.QTY/
(
SELECT SUM(p.QTY)
FROM dataCTE p
WHERE p.Y_ORDER=d.Y_ORDER-1
AND p.Q=d.Q
AND p.NUM=d.NUM
),'9999.99'),'none') WEEK_FILL,
NVL(100*SUM(d.QTY)OVER(PARTITION BY d.Y,d.Q ORDER BY d.DT RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)/
(
SELECT SUM(p.QTY)
FROM dataCTE p
WHERE p.Y_ORDER=d.Y_ORDER-1
AND p.Q=d.Q
AND p.NUM=d.NUM
),100) CURRENT_FILL
FROM dataCTE d
The second variant
WITH dataCTE AS(
SELECT
q.*,
DENSE_RANK()OVER(PARTITION BY q.NUM,q.Q ORDER BY q.Y) Y_ORDER
FROM
(
SELECT
d.*,
EXTRACT(YEAR FROM DT) Y,
-- Q1: JUN, JUL, AUG; Q2: SEP, OCT, NOV; Q3: DEC, JAN, FEB; Q4: MAR, APR, MAY
DECODE(EXTRACT(MONTH FROM DT),6,1,7,1,8,1,9,2,10,2,11,2,12,3,1,3,2,3,3,4,4,4,5,4) Q
FROM TEST_DATA d
) q
)
SELECT
d.*,
d.Y||'Q'||d.Q QTR,
NVL(TO_CHAR(100*d.QTY/p.PREV_QTY,'9999.99'),'none') WEEK_FILL,
NVL(100*SUM(d.QTY)OVER(PARTITION BY d.Y,d.Q ORDER BY d.DT RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)/
p.PREV_QTY,100) CURRENT_FILL
FROM dataCTE d
LEFT JOIN
(
SELECT Y_ORDER,Q,NUM,SUM(QTY) PREV_QTY
FROM dataCTE
GROUP BY Y_ORDER,Q,NUM
) p
ON p.Y_ORDER=d.Y_ORDER-1 AND p.Q=d.Q AND p.NUM=d.NUM
TEST_DATA
is your query
CREATE TABLE TEST_DATA(
A varchar2(20),
B varchar2(20),
C varchar2(20),
NUM number,
E varchar2(20),
QTY number,
DT date
);
INSERT INTO TEST_DATA(A,B,C,NUM,E,QTY,DT)VALUES('Vegetable','carrot','John',1,'Main',14,'26-APR-11');
INSERT INTO TEST_DATA(A,B,C,NUM,E,QTY,DT)VALUES('Vegetable','carrot','John',1,'Main',35,'27-APR-11');
INSERT INTO TEST_DATA(A,B,C,NUM,E,QTY,DT)VALUES('Vegetable','carrot','John',1,'Main', 2,'21-SEP-15');
INSERT INTO TEST_DATA(A,B,C,NUM,E,QTY,DT)VALUES('Vegetable','carrot','John',1,'Main',11,'23-APR-17');
INSERT INTO TEST_DATA(A,B,C,NUM,E,QTY,DT)VALUES('Vegetable','carrot','John',1,'Main',25,'22-MAY-17');
INSERT INTO TEST_DATA(A,B,C,NUM,E,QTY,DT)VALUES('Vegetable','carrot','John',1,'Main',20,'20-APR-18');
INSERT INTO TEST_DATA(A,B,C,NUM,E,QTY,DT)VALUES('Vegetable','onion','John',2,'Extra',23,'02-AUG-16');
INSERT INTO TEST_DATA(A,B,C,NUM,E,QTY,DT)VALUES('Vegetable','onion','John',2,'Extra',32,'07-AUG-16');
INSERT INTO TEST_DATA(A,B,C,NUM,E,QTY,DT)VALUES('Meat','pork','Jane',3,'Main',10,'02-AUG-16');
INSERT INTO TEST_DATA(A,B,C,NUM,E,QTY,DT)VALUES('Meat','pork','Jane',3,'Main',60,'19-JAN-17');
INSERT INTO TEST_DATA(A,B,C,NUM,E,QTY,DT)VALUES('Meat','pork','Jane',3,'Main',12,'25-DEC-17');
SQL Fiddle: 1 - http://sqlfiddle.com/#!4/e7eaa/49 2 - http://sqlfiddle.com/#!4/e7eaa/51
But I think that 80%
for 2018Q4
is mistake because 20/(11+25)=55.56
Upvotes: 1