Forming a sequence of actions from recurring events - sql

I have a table that looks like this:
ID TARGET_ACTION TARGET_DATE
366 0 21.04.2021
186 1 03.04.2021
929 0 14.04.2021
366 1 17.04.2021
Each ID in this table can be repeated and have a different TARGET_ACTION value for a different date. I want to form a sequence of actions for each id, dividing it into weeks so that it looks like this:
ID 01.04.2021-07.04.2021 08.04.2021-14.04.2021 15.04.2021-21.04.2021
366 0 0 1
186 1 1 0
929 0 1 0
How can I do that?

You could use pivoting in this case, though for the whole year there would be 52 week columns.
First, your sample data:
WITH
a_table AS
(
Select 366 "ID", 0 "TARGET_ACTION", To_Date('21.04.2021', 'dd.mm.yyyy') "TARGET_DATE" From Dual Union All
Select 186 "ID", 1 "TARGET_ACTION", To_Date('03.04.2021', 'dd.mm.yyyy') "TARGET_DATE" From Dual Union All
Select 929 "ID", 0 "TARGET_ACTION", To_Date('14.04.2021', 'dd.mm.yyyy') "TARGET_DATE" From Dual Union All
Select 366 "ID", 1 "TARGET_ACTION", To_Date('17.04.2021', 'dd.mm.yyyy') "TARGET_DATE" From DUAL
),
Next thing to do is to join your dataset with some kind of time dimension table. It is a very good thing to have for different uses. The link to how to create one is here: http://oracleolap.blogspot.com/2011/01/script-for-time-dimension-table.html
Instead, I've created a small cte just with weeks from the question:
weeks AS
(
SELECT 14 "WEEK_NUM", To_Date('01.04.2021', 'dd.mm.yyyy') "WEEK_STARTS", To_Date('07.04.2021', 'dd.mm.yyyy') "WEEK_ENDS" From Dual Union All
SELECT 15 "WEEK_NUM", To_Date('08.04.2021', 'dd.mm.yyyy') "WEEK_STARTS", To_Date('14.04.2021', 'dd.mm.yyyy') "WEEK_ENDS" From Dual Union All
SELECT 16 "WEEK_NUM", To_Date('15.04.2021', 'dd.mm.yyyy') "WEEK_STARTS", To_Date('21.04.2021', 'dd.mm.yyyy') "WEEK_ENDS" From Dual
)
Now, if you get the weeks from your data and join them with time dimension you could pivot the resulting dataset. Here is the mainSQL with the result.
SELECT DISTINCT
ID, W14, W15, W16
FROM
(
SELECT
t.ID "ID",
t.TARGET_ACTION "TARGET_ACTION",
To_Char(t.TARGET_DATE, 'WW') "WEEK_NUM",
w.WEEK_STARTS "WEEK_STARTS",
w.WEEK_ENDS "WEEK_ENDS"
FROM
a_table t
INNER JOIN
weeks w ON(To_Char(w.WEEK_NUM) = To_Char(t.TARGET_DATE, 'WW'))
)
PIVOT
(
Count(WEEK_NUM)
FOR WEEK_NUM IN(14 "W14", 15 "W15", 16 "W16")
)
--
-- R e s u l t
--
-- ID W14 W15 W16
-- ---------- ---------- ---------- ----------
-- 929 0 1 0
-- 366 0 0 1
-- 186 1 0 0
Regards...

Related

SQL Oracle - create a new column of dates to calculate a count based on datetime field

I have a table showing subscriptions with a column for active date and a column for inactive date. I need a query which counts the number of active subscriptions for each specific date in a date range.
I'm struggling to add in a row for each date in my date range so that I can then compare with the other date columns in my table.
Example of my table
Example of the result I need
You can do it this way:
-- SAMPLE DATA
WITH
tbl AS
(
Select 'A' "A_TYPE", 1 "SUBSCRIPTION_ID", To_Date('10.10.2022', 'dd.mm.yyyy') "ACTIVE_DATE", Null "INACTIVE_DATE" From Dual Union All
Select 'A' "A_TYPE", 2 "SUBSCRIPTION_ID", To_Date('11.10.2022', 'dd.mm.yyyy') "ACTIVE_DATE", To_Date('14.10.2022', 'dd.mm.yyyy') "INACTIVE_DATE" From Dual Union All
Select 'A' "A_TYPE", 3 "SUBSCRIPTION_ID", To_Date('12.10.2022', 'dd.mm.yyyy') "ACTIVE_DATE", To_Date('14.10.2022', 'dd.mm.yyyy') "INACTIVE_DATE" From Dual Union All
Select 'B' "A_TYPE", 4 "SUBSCRIPTION_ID", To_Date('13.10.2022', 'dd.mm.yyyy') "ACTIVE_DATE", Null "INACTIVE_DATE" From Dual Union All
Select 'B' "A_TYPE", 5 "SUBSCRIPTION_ID", To_Date('14.10.2022', 'dd.mm.yyyy') "ACTIVE_DATE", To_Date('18.10.2022', 'dd.mm.yyyy') "INACTIVE_DATE" From Dual Union All
Select 'B' "A_TYPE", 6 "SUBSCRIPTION_ID", To_Date('15.10.2022', 'dd.mm.yyyy') "ACTIVE_DATE", Null "INACTIVE_DATE" From Dual
),
CTE To generate the dates for A_TYPE:
Here you can define range starting date (09.10.2022) and how many days you want the range to last (LEVEL <= 11)
dates AS
(
Select Distinct
t.A_TYPE "A_TYPE",
d.RANGE_DATE "RANGE_DATE"
From
(Select To_Date('09.10.2022', 'dd.mm.yyyy') + LEVEL - 1 "RANGE_DATE" From dual Connect By LEVEL <= 11) d
Left Join
tbl t ON(1 = 1)
Order By
t.A_TYPE,
d.RANGE_DATE
)
And main SQL:
SELECT
d.A_TYPE "A_TYPE",
d.RANGE_DATE "RANGE_DATE",
(Select Count(*) From tbl Where A_TYPE = d.A_TYPE And ACTIVE_DATE <= d.RANGE_DATE And Nvl(INACTIVE_DATE, To_Date('11.10.2062', 'dd.mm.yyyy')) > d.RANGE_DATE) "ACTIVE_COUNT"
FROM
dates d
This is the result:
/*
A_TYPE RANGE_DATE ACTIVE_COUNT
------ ---------- ------------
A 09-OCT-22 0
A 10-OCT-22 1
A 11-OCT-22 2
A 12-OCT-22 3
A 13-OCT-22 3
A 14-OCT-22 1
A 15-OCT-22 1
A 16-OCT-22 1
A 17-OCT-22 1
A 18-OCT-22 1
A 19-OCT-22 1
B 09-OCT-22 0
B 10-OCT-22 0
B 11-OCT-22 0
B 12-OCT-22 0
B 13-OCT-22 1
B 14-OCT-22 2
B 15-OCT-22 3
B 16-OCT-22 3
B 17-OCT-22 3
B 18-OCT-22 2
B 19-OCT-22 2
*/
Regards...
You can UNPIVOT your two date columns and then use a PARTITIONed OUTER JOIN to a calendar:
WITH data (type, subscription_id, is_active, dt) AS (
SELECT type, subscription_id, is_active, dt
FROM table_name
UNPIVOT (
dt FOR is_active IN (
active_date AS 1,
inactive_date AS 0
)
)
)
SELECT d.type,
c.day,
COUNT(CASE d.is_active WHEN 1 THEN 1 END) AS count_active,
COUNT(CASE d.is_active WHEN 0 THEN 1 END) AS count_inactive
FROM (
SELECT TRUNC(min_dt) + LEVEL - 1 AS day
FROM (
SELECT MIN(dt) AS min_dt,
MAX(dt) AS max_dt
FROM data
)
CONNECT BY TRUNC(min_dt) + LEVEL - 1 < max_dt
) c
LEFT OUTER JOIN data d
PARTITION BY (d.type)
ON (c.day <= d.dt AND d.dt < c.day + 1)
GROUP BY
d.type,
c.day
ORDER BY
d.type,
c.day
Which, for the sample data:
CREATE TABLE table_name (type, subscription_id, active_date, inactive_date) AS
SELECT 'A', 1, DATE '2022-11-01', NULL FROM DUAL UNION ALL
SELECT 'A', 2, DATE '2022-11-02', DATE '2022-11-10' FROM DUAL UNION ALL
SELECT 'A', 3, DATE '2022-11-03', NULL FROM DUAL UNION ALL
SELECT 'A', 4, DATE '2022-11-04', NULL FROM DUAL UNION ALL
SELECT 'B', 5, DATE '2022-11-05', NULL FROM DUAL UNION ALL
SELECT 'B', 6, DATE '2022-11-06', NULL FROM DUAL UNION ALL
SELECT 'B', 7, DATE '2022-11-07', DATE '2022-11-09' FROM DUAL UNION ALL
SELECT 'B', 8, DATE '2022-11-08', NULL FROM DUAL;
Outputs:
TYPE
DAY
COUNT_ACTIVE
COUNT_INACTIVE
A
01-NOV-22
1
0
A
02-NOV-22
1
0
A
03-NOV-22
1
0
A
04-NOV-22
1
0
A
05-NOV-22
0
0
A
06-NOV-22
0
0
A
07-NOV-22
0
0
A
08-NOV-22
0
0
A
09-NOV-22
0
0
B
01-NOV-22
0
0
B
02-NOV-22
0
0
B
03-NOV-22
0
0
B
04-NOV-22
0
0
B
05-NOV-22
1
0
B
06-NOV-22
1
0
B
07-NOV-22
1
0
B
08-NOV-22
1
0
B
09-NOV-22
0
1
fiddle
SELECT
type,
TO_DATE(date, 'DD-MM-YYYY') as date,
count(date) AS count_of_dates
FROM table
GROUP BY type, date
ORDER BY type

SQL Implementing Forward Fill logic

I have a dataset within a date range which has three columns, Product_type, date and metric. For a given product_type, data is not available for all days. For the missing rows, we would like to do a forward date fill for next n days using the last value of the metric.
Product_type
date
metric
A
2019-10-01
10
A
2019-10-02
12
A
2019-10-03
15
A
2019-10-04
5
A
2019-10-05
5
A
2019-10-06
5
A
2019-10-16
12
A
2019-10-17
23
A
2019-10-18
34
Here, the data from 2019-10-04 to 2019-10-06, has been forward filled. There might be bigger gaps in the dates, but we only want to fill the first n days.
Here, n=2, so rows 5 and 6 has been forward filled.
I am not sure how to implement this logic in SQL.
Here's one option. Read comments within code.
Sample data:
SQL> WITH
2 test (product_type, datum, metric)
3 AS
4 (SELECT 'A', DATE '2019-10-01', 10 FROM DUAL
5 UNION ALL
6 SELECT 'A', DATE '2019-10-02', 12 FROM DUAL
7 UNION ALL
8 SELECT 'A', DATE '2019-10-03', 15 FROM DUAL
9 UNION ALL
10 SELECT 'A', DATE '2019-10-04', 5 FROM DUAL
11 UNION ALL
12 SELECT 'A', DATE '2019-10-16', 12 FROM DUAL
13 UNION ALL
14 SELECT 'A', DATE '2019-10-18', 23 FROM DUAL),
Query begins here:
15 temp
16 AS
17 -- CB_FWD_FILL = 1 if difference between two consecutive dates is larger than 1 day
18 -- (i.e. that's the gap to be forward filled)
19 (SELECT product_type,
20 datum,
21 metric,
22 LEAD (datum) OVER (PARTITION BY product_type ORDER BY datum)
23 next_datum,
24 CASE
25 WHEN LEAD (datum)
26 OVER (PARTITION BY product_type ORDER BY datum)
27 - datum >
28 1
29 THEN
30 1
31 ELSE
32 0
33 END
34 cb_fwd_fill
35 FROM test)
36 -- original data from the table
37 SELECT product_type, datum, metric FROM test
38 UNION ALL
39 -- DATUM is the last date which is OK; add LEVEL pseudocolumn to it to fill the gap
40 -- with PAR_N number of rows
41 SELECT product_type, datum + LEVEL, metric
42 FROM (SELECT product_type, datum, metric
43 FROM (-- RN = 1 means that that's the first gap in data set - that's the one
44 -- that has to be forward filled
45 SELECT product_type,
46 datum,
47 metric,
48 ROW_NUMBER ()
49 OVER (PARTITION BY product_type ORDER BY datum) rn
50 FROM temp
51 WHERE cb_fwd_fill = 1)
52 WHERE rn = 1)
53 CONNECT BY LEVEL <= &par_n
54 ORDER BY datum;
Result:
Enter value for par_n: 2
PRODUCT_TYPE DATUM METRIC
--------------- ---------- ----------
A 2019-10-01 10
A 2019-10-02 12
A 2019-10-03 15
A 2019-10-04 5
A 2019-10-05 5 --> newly added
A 2019-10-06 5 --> rows
A 2019-10-16 12
A 2019-10-18 23
8 rows selected.
SQL>
Another solution:
WITH test (product_type, datum, metric) AS
(
SELECT 'A', DATE '2019-10-01', 10 FROM DUAL
UNION ALL
SELECT 'A', DATE '2019-10-02', 12 FROM DUAL
UNION ALL
SELECT 'A', DATE '2019-10-03', 15 FROM DUAL
UNION ALL
SELECT 'A', DATE '2019-10-04', 5 FROM DUAL
UNION ALL
SELECT 'A', DATE '2019-10-16', 12 FROM DUAL
UNION ALL
SELECT 'A', DATE '2019-10-18', 23 FROM DUAL
),
minmax(mindatum, maxdatum) AS (
SELECT MIN(datum), max(datum) from test
),
alldates (datum, product_type) AS
(
SELECT mindatum + level - 1, t.product_type FROM minmax,
(select distinct product_type from test) t
connect by mindatum + level <= (select maxdatum from minmax)
),
grouped as (
select a.datum, a.product_type, t.metric,
count(t.product_type) over(partition by a.product_type order by a.datum) as grp
from alldates a
left join test t on t.datum = a.datum
),
final_table as (
select g.datum, g.product_type, g.grp, g.rn,
last_value(g.metric ignore nulls) over(partition by g.product_type order by g.datum) as metric
from (
select g.*, row_number() over(partition by product_type, grp order by datum) - 1 as rn
from grouped g
) g
)
select datum, product_type, metric
from final_table
where rn <= &par_n
order by datum
;

sql: generate additional dates depending on the period

Got data like this:
date_start
date_end
rate
01.04.2022
20.04.2022
1
21.04.2022
11.05.2022
7
12.05.2022
15.07.2022
5
And i need get separete dates between start\end month, like this:
date_start
date_end
rate
01.04.2022
20.04.2022
1
21.04.2022
30.04.2022
7
01.05.2022
11.05.2022
7
12.05.2022
31.05.2022
5
01.06.2022
30.06.2022
5
01.07.2022
15.07.2022
5
any ideas?
found a solution, everything works correctly on different arrays of dates, but it seems to me that there may be a much simpler and more concise solution for this case?
code below:
select d_surcharge_period_from,
d_surcharge_period_to,
case
when column_value = 1 then
d_surcharge_period_from
when column_value > 1 then
trunc(add_months(d_surcharge_period_from, column_value - 1), 'mm')
end as period_beg,
case
when lead(column_value) over(order by d_surcharge_period_from, column_value) = 1 then
d_surcharge_period_to
else
last_day(add_months(d_surcharge_period_from, column_value - 1))
end period_end,
n_rate_value,
column_value
from (select to_date('01.04.2022', 'dd.mm.yyyy') as d_surcharge_period_from,
to_date('20.04.2022', 'dd.mm.yyyy') as d_surcharge_period_to,
1 n_rate_value,
0 as n_used
from dual
union all
select to_date('21.04.2022', 'dd.mm.yyyy') as d_surcharge_period_from,
to_date('11.05.2022', 'dd.mm.yyyy') as d_surcharge_period_to,
7 n_rate_value,
0 as n_used
from dual
union all
select to_date('12.05.2022', 'dd.mm.yyyy') as d_surcharge_period_from,
to_date('15.07.2022', 'dd.mm.yyyy') as d_surcharge_period_to,
5 n_rate_value,
0 as n_used
from dual),
table(cast(multiset (select level
from dual
connect by add_months(trunc(d_surcharge_period_from, 'MM'), level - 1) <= d_surcharge_period_to) as sys.odcinumberlist))
order by d_surcharge_period_from,
column_value

Split date range into weeks in sql

Given a table called Project, I need the list of team_id's who won at least an award every week in last 3 months
launch_date team_id project_name
2019-01-01 123 A
2019-01-01 345 B
2019-01-01 357 C
2019-01-09 123 D
2019-01-08 345 E
2019-01-21 123 F
project_name award
A Y
B N
C Y
D Y
E N
F Y
last 3 months can be achieved with below where condition but how do i split the launch_date into weekly intervals
where launch_date >= sysdate - 90
With the given data, answer should be team id 123
In your sample data, You have only given 21 days of data instead of 3 months.
You can find out the total number of weeks and their week starting date which can then be compared with your table data to check if an award is won by the team for each week as follows:
SQL> --SAMPLE DATA
SQL> with teams (launch_date, team_id, project_name)
2 as
3 (SELECT DATE'2019-01-01', 123, 'A' FROM DUAL UNION ALL
4 SELECT DATE'2019-01-01', 345, 'B' FROM DUAL UNION ALL
5 SELECT DATE'2019-01-01', 357, 'C' FROM DUAL UNION ALL
6 SELECT DATE'2019-01-09', 123, 'D' FROM DUAL UNION ALL
7 SELECT DATE'2019-01-08', 345, 'E' FROM DUAL UNION ALL
8 SELECT DATE'2019-01-21', 123, 'F' FROM DUAL),
9 AWARDS(project_name, award)
10 AS
11 (SELECT 'A','Y' FROM DUAL UNION ALL
12 SELECT 'B','N' FROM DUAL UNION ALL
13 SELECT 'C','Y' FROM DUAL UNION ALL
14 SELECT 'D','Y' FROM DUAL UNION ALL
15 SELECT 'E','N' FROM DUAL UNION ALL
16 SELECT 'F','Y' FROM DUAL),
17 -- YOUR QUERY START FROM HERE
18 -- WITH
19 WKS(DT) AS
20 (SELECT DISTINCT TRUNC(DATE '2019-01-21' - LEVEL + 1, 'W')
21 FROM DUAL CONNECT BY LEVEL <= 21
22 )
23 SELECT T.TEAM_ID
24 FROM WKS W
25 LEFT JOIN TEAMS T ON W.DT = TRUNC(T.LAUNCH_DATE, 'W')
26 LEFT JOIN AWARDS A ON A.PROJECT_NAME = T.PROJECT_NAME
27 WHERE A.AWARD = 'Y'
28 GROUP BY T.TEAM_ID
29 HAVING COUNT(1) = ( SELECT COUNT(1) FROM WKS);
TEAM_ID
----------
123
SQL>
In WKS cte for 3 months data, You need to replace the
WKS(DT) AS
(SELECT DISTINCT TRUNC(DATE '2019-01-21' - LEVEL + 1, 'W')
FROM DUAL CONNECT BY LEVEL <= 21
)
with
WKS(DT) AS
( SELECT DISTINCT TRUNC(sysdate - LEVEL + 1, 'W')
FROM DUAL CONNECT BY LEVEL <= trunc(sysdate) - add_months(trunc(sysdate), -3
)

How to get data for previous 7 days based on set of dates in groups in sql

I was going through this forum for my query to get data for previous 7 days,but most of them give it for current date.Below is my requirement:
I have a Table 1 as below:
These are start dates of week which is monday
from_date
2016-01-04
2016-01-11
2016-01-18
Table 2
I have all days of week here starting from monday.Ex: jan 04 - monday to jan 10 - sunday and so on for other weeks also.
get_date flag value
2016-01-04 N 4
2016-01-05 N 9
2016-01-06 Y 2
2016-01-07 Y 13
2016-01-08 Y 7
2016-01-09 Y 8
2016-01-10 Y 8
2016-01-11 Y 1
2016-01-12 Y 9
2016-01-13 N 8
2016-01-14 N 24
2016-01-15 N 8
2016-01-16 Y 4
2016-01-17 Y 5
2016-01-18 Y 9
2016-01-19 Y 2
2016-01-20 Y 8
2016-01-21 Y 4
2016-01-22 N 9
2016-01-23 N 87
2016-01-24 Y 3
Expected Result
here wk is the unique number for each start-end dates respectively
avg value is the avg of the values for the dates in that week.
last 2 days of the week are weekend days.
say 2016-01-09 and 2016-01-10 are weekends
from_date get_date Wk Total_days Total_weekdays_flag_Y Total_weekenddays_flag_Y Avg_value
2016-01-04 2016-01-10 1 7 3 2 6.714285714
2016-01-11 2016-01-17 2 7 2 2 8.428571429
2016-01-18 2016-01-24 3 7 4 1 17.42857143
Could anyone help me with this as I am not good at sql.
Thanks
select
from_date
, Wk
, count(case when day_of_week <=5 and flag = 'Y' then 1 end) as Total_weekdays_flag_Y
, count(case when day_of_week > 5 and flag = 'Y' then 1 end) as Total_weekenddays_flag_Y
, avg(value) as Avg_value
from (
select trunc(get_date,'IW') as from_date
, (trunc(get_date,'IW')- trunc(date'2016-01-04','IW'))/7 + 1 as Wk
, flag
, value
, get_date - trunc(get_date,'IW') as day_of_week
from Table_2)
group by from_date, Wk
order by from_date, Wk;
EDIT:
/*generate some test_data for table 2*/
with table_2 (get_date, flag, value) as (
select date'2016-01-03' + level,
DECODE(mod(level,3),0,'Y','N'),
round(dbms_random.value(0,10))
from dual connect by level < 101
),
/*generate some test_weeks for table 1*/
table_1 (FROM_date) as (select date'2016-01-04' + (level-1)*7 from dual connect by level < 101 )
/*main query */
select
from_date
, Wk
, count(day_of_week) as total
, count(case when day_of_week <=5 and flag = 'Y' then 1 end) as Total_weekdays_flag_Y
, count(case when day_of_week > 5 and flag = 'Y' then 1 end) as Total_weekenddays_flag_Y
, avg(value) as Avg_value
from (
select last_value(from_date ignore nulls) over (order by get_date) as from_date
,last_value(Wk ignore nulls) over (order by get_date) as Wk
, flag
, value
, get_date - trunc(get_date,'IW') as day_of_week
from Table_2 t2
full join (select row_number() over (order by from_date) as wk,from_date from table_1) t1 on t2.get_date = t1.from_date
)
group by from_date, Wk
having count(day_of_week) > 0
order by from_date, Wk
In the query below, I create the test data right within the query; in final form, you would delete the subqueries table_1 and table_2 and use the rest.
The syntax will work from Oracle 11.2 on. In Oracle 11.1, you need to move the column names in factored subqueries to the select... from dual part. Or, since you really only have one subquery (prep) and an outer query, you can write prep as an actual, in-line subquery.
Your arithmetic seems off on the average for the first week.
In your sample output you use get_date for the last day of the week. That is odd, since in table_2 that name has a different meaning. I used to_date in my output. I also do not show total_days - that is always 7, so why include it at all? (If it is not always 7, then there is something you didn't tell us; anyway, a count(...), if that is what it should be, is easy to add).
with
-- begin test data, can be removed in final solution
table_1 ( from_date ) as (
select date '2016-01-04' from dual union all
select date '2016-01-11' from dual union all
select date '2016-01-18' from dual
)
,
table_2 ( get_date, flag, value ) as (
select date '2016-01-04', 'N', 4 from dual union all
select date '2016-01-05', 'N', 9 from dual union all
select date '2016-01-06', 'Y', 2 from dual union all
select date '2016-01-07', 'Y', 13 from dual union all
select date '2016-01-08', 'Y', 7 from dual union all
select date '2016-01-09', 'Y', 8 from dual union all
select date '2016-01-10', 'Y', 8 from dual union all
select date '2016-01-11', 'Y', 1 from dual union all
select date '2016-01-12', 'Y', 9 from dual union all
select date '2016-01-13', 'N', 8 from dual union all
select date '2016-01-14', 'N', 24 from dual union all
select date '2016-01-15', 'N', 8 from dual union all
select date '2016-01-16', 'Y', 4 from dual union all
select date '2016-01-17', 'Y', 5 from dual union all
select date '2016-01-18', 'Y', 9 from dual union all
select date '2016-01-19', 'Y', 2 from dual union all
select date '2016-01-20', 'Y', 8 from dual union all
select date '2016-01-21', 'Y', 4 from dual union all
select date '2016-01-22', 'N', 9 from dual union all
select date '2016-01-23', 'N', 87 from dual union all
select date '2016-01-24', 'Y', 3 from dual
),
-- end test data, continue actual query
prep ( get_date, flag, value, from_date, wd_flag ) as (
select t2.get_date, t2.flag, t2.value, t1.from_date,
case when t2.get_date - t1.from_date <= 4 then 'wd' else 'we' end
from table_1 t1 inner join table_2 t2
on t2.get_date between t1.from_date and t1.from_date + 6
)
select from_date,
from_date + 6 as to_date,
row_number() over (order by from_date) as wk,
count(case when flag = 'Y' and wd_flag = 'wd' then 1 end)
as total_weekday_Y,
count(case when flag = 'Y' and wd_flag = 'we' then 1 end)
as total_weekend_Y,
round(avg(value), 6) as avg_value
from prep
group by from_date;
Output:
FROM_DATE TO_DATE WK TOTAL_WEEKDAY_Y TOTAL_WEEKEND_Y AVG_VALUE
---------- ---------- ---- --------------- --------------- ----------
2016-01-04 2016-01-10 1 3 2 7.285714
2016-01-11 2016-01-17 2 2 2 8.428571
2016-01-18 2016-01-24 3 4 1 17.428571