The goal is to combine Time_a within 10 min interval that has same ID.
And group the ID.
ID Time_a -> ID
------------ ----------
1 12:10:00 1
1 12:15:00 2
1 12:20:00 2
2 12:25:00
2 12:35:00
2 02:00:00
It became two '2' because time interval between row5 and row6 is more than 10 min.
I was able to combine within 10-min difference, but it doesn't distinguish ID.
select ID
from(
select id, Time_a, min(time) OVER (order by id, time rows between 1 preceding and 1 preceding) prev_t_stamp
from dual
)
where abs(Time_a-prev_t_stamp)>10/1440
If time_a is date then it works as follow. If it is a timestamp you need to cast it to a date otherwise it will not quite work. Here is my test script
drop table test;
create table test (id number, time_a date);
insert into test values (1, to_date('12:10','HH24:MI'));
insert into test values (1, to_date('12:15','HH24:MI'));
insert into test values (1, to_date('12:20','HH24:MI'));
insert into test values (2, to_date('12:25','HH24:MI'));
insert into test values (2, to_date('12:35','HH24:MI'));
insert into test values (2, to_date('14:00','HH24:MI'));
select id from (
select distinct id, case from (
select ID,case when abs(Time_a-prev_t_stamp)>10/1440 then '>' end case
from(
select id, Time_a, min(time_a) OVER (order by id, time_a rows between 1 preceding and 1 preceding) prev_t_stamp
from test
)
)
) order by 1
This results into:
table TEST dropped.
table TEST created.
1 rows inserted.
1 rows inserted.
1 rows inserted.
1 rows inserted.
1 rows inserted.
1 rows inserted.
ID
--
1
2
2
Related
I have a table like:
ID ID2 Name
1 1
2 1
3 2
4 2
5 2
6 3
7 3
8 3
I want to Update the Name column with Values like Name1, name 2 and so on.
This will be based on condition if there are two similar values in ID2 column, for example, the first two rows, then the Name column to be updated with values Name1 and Name2 respectively.Next rows would be Name1, Name2, Name3 respectively and so on. Can someone help me with the logic for this?
ROW_NUMBER with a partition on the ID2 column, ordered by the ID column, should generate the sequences you want. Try this update query:
UPDATE yourTable t1
SET Name = (SELECT 'Name' || t.rn FROM
(
SELECT t2.ID, t2.ID2,
ROW_NUMBER() OVER (PARTITION BY t2.ID2 ORDER BY t2.ID) rn
FROM yourTable t2
WHERE t1.ID = t2.ID AND t1.ID2 = t2.ID2
) t)
I currently have a table where I have number of units sold and the week that they are sold in. I am trying to get the average of the prior six weeks of units sold. I am using the Fiscal EOW date as the date to show the units sold. I am stumped on this problem.
I am using the following:
select
b.FISC_EOW_DT,
a.*,
avg(net_unit_qty) over (partition by sid order by FISC_EOW_DT rows between 5
preceding and current row) as avsaleslast6wk
FROM tbl1 a
JOIN (SELECT DISTINCT FISC_WK_OF_MTH_ID,FISC_EOW_DT FROM tbl2 ) B
ON B.FISC_WK_OF_MTH_ID=A.FISC_WK_OF_MTH_ID
where sid = 12345
This works however it calculates the last 5 rows, regardless if they are the previous week or not. So for example:
if the weeks was:
12/01/2016
01/08/2017
06/01/2017
08/01/2017
It will calculate the average of these 4 weeks even though they are not consecutive. I need to know how to calculate the Average sales including weeks that are not consecutive. So for the week going back from:
01/08/2017
to
06/01/2017
there would be 0 for average sales since the last 6 weeks are not represented.
Any help would be greatly appreciated.
TBL1
SID FISC_EOW_DT NET_UNIT_QTY
1234 01/01/2017 1
1234 01/08/2017 2
1234 01/15/2017 3
1234 01/22/2017 2
1234 01/29/2017 1
1234 06/09/2017 1
Expected result:
SID FISC_EOW_DT NET_UNIT_QTY AVSALESLAST6WEEKS
1234 01/01/2017 1 0(0+0+0+0+0+0)/6
1234 01/08/2017 2 .167(1+0+0+0+0+0)/6
1234 01/15/2017 3 .50(2+1+0+0+0+0)/6
1234 01/21/2017 2 1(3+2+1+0+0+0)/6
1234 01/28/2017 1 1.33(2+3+2+1+0+0)/6
1234 06/09/2017 1 0(0+0+0+0+0+0)6<----SINCE THERE HAVE BEEN NO SALES FOR MULTIPLE WEEKS
I would like to account for the weeks where there have been no sales. So I will need to create the blank weeks through coding, however I am not sure how to do that.
SELECT
D1_PROD_11_SKU_ID
,D4_TIME_01_FISC_WK_OF_MTH_ID
,FISC_EOW_DT
,net_unit_qty
,(
CASE WHEN Min(FISC_EOW_DT)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 1 Preceding AND current row) >= FISC_EOW_DT - 6*7
THEN Min(net_unit_qty)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 1 Preceding AND current row)
ELSE 0
END
+
CASE WHEN Min(FISC_EOW_DT)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 1 Preceding AND 1 Preceding) >= FISC_EOW_DT -6*7
THEN Min(net_unit_qty)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 1 Preceding AND 1 Preceding)
ELSE 0
END
+ CASE WHEN Min(FISC_EOW_DT)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 2 Preceding AND 2 Preceding) >= FISC_EOW_DT - 6*7
THEN Min(net_unit_qty)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 2 Preceding AND 2 Preceding)
ELSE 0
END
+ CASE WHEN Min(FISC_EOW_DT)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 3 Preceding AND 3 Preceding) >= FISC_EOW_DT - 6*7
THEN Min(net_unit_qty)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 3 Preceding AND 3 Preceding)
ELSE 0
END
+ CASE WHEN Min(FISC_EOW_DT)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 4 Preceding AND 4 Preceding) >= FISC_EOW_DT - 6*7
THEN Min(net_unit_qty)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 4 Preceding AND 4 Preceding)
ELSE 0
END
+ CASE WHEN Min(FISC_EOW_DT)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 5 Preceding AND 5 Preceding) >= FISC_EOW_DT - 6*7
THEN Min(net_unit_qty)
Over (PARTITION BY D1_PROD_11_SKU_ID ORDER BY FISC_EOW_DT ROWS BETWEEN 5 Preceding AND 5 Preceding)
ELSE 0
END
) AS ROLLING_SIX_WEEK_SALES
FROM TBL1
This utilizes EXPAND ON to create the missing rows with a zero quantity, applies the average and finally removes the added rows again:
SELECT
SID
,Begin(pd) AS eow_dt
-- set the quantity to zero for non-existing weeks
,CASE WHEN FISC_EOW_DT = Begin(pd) THEN net_unit_qty ELSE 0 END AS qty
-- finally calculate the average of the previous 5 plus the current row
,Sum(qty)
Over (PARTITION BY sid
ORDER BY Begin(pd)
ROWS 5 Preceding) / 6.000 AS avsaleslast6wk
FROM
(
SELECT
SID
,FISC_EOW_DT
,NET_UNIT_QTY
,pd
FROM
(
SELECT
SID
,FISC_EOW_DT
,NET_UNIT_QTY
-- first: find the next existing row using LEAD
,Coalesce(Min(FISC_EOW_DT)
Over (PARTITION BY SID
ORDER BY FISC_EOW_DT
ROWS BETWEEN 1 Following AND 1 Following )
,FISC_EOW_DT+7) AS next_week
FROM tbl1
) AS dt
-- then: create the missing weeks
EXPAND ON PERIOD(FISC_EOW_DT, next_week) AS pd BY INTERVAL '7' DAY
) AS dt
-- remove the non-existing weeks again
QUALIFY qty > 0
ORDER BY 1,2
Edit:
Of course this assumes that there's only a single row per week.
Another solution uses a brute force approach which is ok for a small number of weeks: check if each of the previous 6 rows is within the range of 6 weeks, then add the quantity.
SELECT
SID
,FISC_EOW_DT
,net_unit_qty
,(CASE WHEN Min(FISC_EOW_DT)
Over (PARTITION BY sid ORDER BY FISC_EOW_DT ROWS BETWEEN 1 Preceding AND 1 Preceding) >= FISC_EOW_DT - 5*7
THEN Min(net_unit_qty)
Over (PARTITION BY sid ORDER BY FISC_EOW_DT ROWS BETWEEN 1 Preceding AND 1 Preceding)
ELSE 0
END
+ CASE WHEN Min(FISC_EOW_DT)
Over (PARTITION BY sid ORDER BY FISC_EOW_DT ROWS BETWEEN 2 Preceding AND 2 Preceding) >= FISC_EOW_DT - 5*7
THEN Min(net_unit_qty)
Over (PARTITION BY sid ORDER BY FISC_EOW_DT ROWS BETWEEN 2 Preceding AND 2 Preceding)
ELSE 0
END
+ CASE WHEN Min(FISC_EOW_DT)
Over (PARTITION BY sid ORDER BY FISC_EOW_DT ROWS BETWEEN 3 Preceding AND 3 Preceding) >= FISC_EOW_DT - 5*7
THEN Min(net_unit_qty)
Over (PARTITION BY sid ORDER BY FISC_EOW_DT ROWS BETWEEN 3 Preceding AND 3 Preceding)
ELSE 0
END
+ CASE WHEN Min(FISC_EOW_DT)
Over (PARTITION BY sid ORDER BY FISC_EOW_DT ROWS BETWEEN 4 Preceding AND 4 Preceding) >= FISC_EOW_DT - 5*7
THEN Min(net_unit_qty)
Over (PARTITION BY sid ORDER BY FISC_EOW_DT ROWS BETWEEN 4 Preceding AND 4 Preceding)
ELSE 0
END
+ CASE WHEN Min(FISC_EOW_DT)
Over (PARTITION BY sid ORDER BY FISC_EOW_DT ROWS BETWEEN 5 Preceding AND 5 Preceding) >= FISC_EOW_DT - 5*7
THEN Min(net_unit_qty)
Over (PARTITION BY sid ORDER BY FISC_EOW_DT ROWS BETWEEN 5 Preceding AND 5 Preceding)
ELSE 0
END
+ net_unit_qty
) / 6.000 AS avsaleslast6wk
FROM tbl1
This is a lot of cut & paste & modify, but probably quite efficient, a single step.
Looking into your sample data and desired output, I think you are looking for sum of previous 6 weeks divided by 6 and reset when there is gap between weeks, in this case below can be an option.
WITH difference (
sid
,FISC_EOW_DT
,diff
)
AS (
SELECT t1.sid
,t1.FISC_EOW_DT
,t1.FISC_EOW_DT - Min(t1.FISC_EOW_DT) OVER (
ORDER BY t1.FISC_EOW_DT ROWS BETWEEN 1 preceding
AND 1 preceding
) AS diff
FROM table1 t1
)
SELECT t.sid
,t.FISC_EOW_DT
,t.NET_UNIT_QTY
,coalesce(cast(SUM(t.NET_UNIT_QTY) OVER (
ORDER BY t.FISC_EOW_DT RESET WHEN d.diff > 7 ROWS BETWEEN 7 preceding
AND 1 preceding
) AS DECIMAL(4, 3)) / 6, 0) AS AverageCalc
FROM difference d
INNER JOIN table1 t ON d.sid = t.sid
AND d.FISC_EOW_DT = t.FISC_EOW_DT;
what the query does is that derived table calculate the difference of dates between current and preceding row and in main query, the difference is used as reset if its more than 7 determining that weeks are not continuous.
Result:
SID FISC_EOW_DT NET_UNIT_QTY AverageCalc
---- ----------- ------------ ---------
1234 2017-01-01 1 0.000
1234 2017-01-08 2 0.167
1234 2017-01-15 3 0.500
1234 2017-01-22 2 1.000
1234 2017-01-29 1 1.333
1234 2017-06-09 1 0.000
PFB screenshot FYR.
SQLite UPDATE Statement
I have two tables:
Table1
ID Num
1
2
3
4
5
Table2
ID
1
1
2
2
2
3
3
4
4
4
5
I need to UPDATE the Num field in Table1 with occurences of the ID field in Table2 i.e. based on previous:
Table1
ID Num
1 2
2 3
3 2
4 3
5 1
If i run this SQLite statement:
SELECT COUNT(t2.ID) FROM Table1 t1,Table2 t2 WHERE t1.ID=t2.ID GROUP BY t2.ID;
i have the correct table but when i try to UPDATE with that statement:
UPDATE Table1
SET Num=(SELECT COUNT(t2.ID) FROM Table1 t1,Table2 t2 WHERE t1.ID=t2.ID GROUP BY t2.ID);
i have nonsense output.Any ideas?
You must use a correlated subquery to correlate the value returned by the subquery with the current row in the outer query.
This means that you must not use Table1 again in the subquery, but instead refer to the outer table (with the actual name; the UPDATEd table does not support an alias):
UPDATE Table1
SET Num = (SELECT COUNT(t2.ID)
FROM Table2 t2
WHERE Table1.ID=t2.ID
GROUP BY t2.ID);
I have a dataframe data like this
data
id time var1
1 a 3 0
2 a 2 2
3 a 1 3
4 b 3 2
5 b 4 6
I want to get the second largest time row of each id like this:
data2
id time var1
1 a 2 2
2 b 3 2
I try use sqldf
sqldf("select * from data order by time desc limit 2,1 group by id")
but I got an Error:
Error in sqliteSendQuery(con, statement, bind.data) :
error in statement: near "group": syntax error
I also try:
select max(time),* from data where time not in(select max(time) from data group by id) group by id
but I only got a result, I can't get the right answer.
Thanks !
Try taking the maximum among the rows with values less than the maximum for that id:
sqldf("select id, max(time) time, var1
from data a
where time < (select max(b.time)
from data b
where b.id = a.id)
group by id")
I have some data that looks like this:
ID flag
A 1
A 1
A 2
B 1
B 2
B 3
How do I use proc sql to count the Id by flag so that the outcome looks like this?:
ID flag count
A 1 2
A 2 1
B 1 1
B 2 1
B 3 1
The query I used does not seem to be correct since it returns the distinct types of flag, not how many of each type of flag there are.
proc sql;
select Id, flag, count(flag) as count from table
group by Id;
You need to include flag in your grouping.
proc sql;
select Id, flag, count(1) as count from table
group by Id, flag;
quit;