Oracle - Find nearest values and date difference - sql

I have two table:
table1
user start end parameter
1 1 jan 2010 31 mar 2010 abc
1 1 apr 2010 30 jun 2010 abc
1 1 jan 2010 31 mar 2010 xyz
1 1 apr 2010 30 jun 2010 xyz
1 1 jan 2010 31 mar 2010 qqq
1 1 apr 2010 30 jun 2010 qqq
table2
start end parameter value
1 jan 2009 31 mar 2009 abc 100
1 apr 2009 30 jun 2009 abc 200
1 jan 2009 31 mar 2009 xyz 300
1 apr 2009 30 jun 2009 xyz 400
1 jan 2009 31 mar 2009 qqq 500
1 apr 2009 30 jun 2009 qqq 600
I have to associate the 2 tables based on parameter, start and end. I need to find the nearest values. So, for ex. 1 jan 2010 - 31 mar 2010 for parameter abc, we don't have any values in table2, so get the nearest value, i.e. 1 apr 2009 - 30 jun 2009 with parameter abc and associate value 200. Also, find the difference of days from start of both tables.
The resulting table should look like:
table3:
user start end parameter value diff
1 1 jan 2010 31 mar 2010 abc 200 270 days
1 1 apr 2010 30 jun 2010 abc 200 365 days
1 1 jan 2010 31 mar 2010 xyz 400 270 days
1 1 apr 2010 30 jun 2010 xyz 400 365 days
1 1 jan 2010 31 mar 2010 qqq 600 270 days
1 1 apr 2010 30 jun 2010 qqq 600 365 days

Here's one way:
with table1 as (select 1 usr, to_date('01/01/2010', 'dd/mm/yyyy') start_date, to_date('31/03/2010', 'dd/mm/yyyy') end_date, 'abc' parameter from dual union all
select 1 usr, to_date('01/04/2010', 'dd/mm/yyyy') start_date, to_date('30/06/2010', 'dd/mm/yyyy') end_date, 'abc' parameter from dual union all
select 1 usr, to_date('01/01/2010', 'dd/mm/yyyy') start_date, to_date('31/03/2010', 'dd/mm/yyyy') end_date, 'xyz' parameter from dual union all
select 1 usr, to_date('01/04/2010', 'dd/mm/yyyy') start_date, to_date('30/06/2010', 'dd/mm/yyyy') end_date, 'xyz' parameter from dual union all
select 1 usr, to_date('01/01/2010', 'dd/mm/yyyy') start_date, to_date('31/03/2010', 'dd/mm/yyyy') end_date, 'qqq' parameter from dual union all
select 1 usr, to_date('01/04/2010', 'dd/mm/yyyy') start_date, to_date('30/06/2010', 'dd/mm/yyyy') end_date, 'qqq' parameter from dual),
table2 as (select 1 usr, to_date('01/01/2009', 'dd/mm/yyyy') start_date, to_date('31/03/2009', 'dd/mm/yyyy') end_date, 'abc' parameter, 100 value from dual union all
select 1 usr, to_date('01/04/2009', 'dd/mm/yyyy') start_date, to_date('30/06/2009', 'dd/mm/yyyy') end_date, 'abc' parameter, 200 value from dual union all
select 1 usr, to_date('01/01/2009', 'dd/mm/yyyy') start_date, to_date('31/03/2009', 'dd/mm/yyyy') end_date, 'xyz' parameter, 300 value from dual union all
select 1 usr, to_date('01/04/2009', 'dd/mm/yyyy') start_date, to_date('30/06/2009', 'dd/mm/yyyy') end_date, 'xyz' parameter, 400 value from dual union all
select 1 usr, to_date('01/01/2009', 'dd/mm/yyyy') start_date, to_date('31/03/2009', 'dd/mm/yyyy') end_date, 'qqq' parameter, 500 value from dual union all
select 1 usr, to_date('01/04/2009', 'dd/mm/yyyy') start_date, to_date('30/06/2009', 'dd/mm/yyyy') end_date, 'qqq' parameter, 600 value from dual)
-- end of mimicking your tables; see SQL below:
select usr,
start_date,
end_date,
parameter,
latest_value,
diff_days
from (select usr,
start_date,
end_date,
parameter,
last_value(value ignore nulls) over (partition by usr, parameter order by start_date) latest_value,
start_date - last_value(case when value is not null then start_date end ignore nulls) over (partition by usr, parameter order by start_date) diff_days
from (select usr,
start_date,
end_date,
parameter,
cast(null as number) value
from table1
union all
select usr,
start_date,
end_date,
parameter,
value
from table2))
where diff_days > 0;
USR START_DATE END_DATE PARAMETER LATEST_VALUE DIFF_DAYS
---------- ----------- ----------- --------- ------------ ----------
1 01 jan 2010 31 mar 2010 abc 200 275
1 01 apr 2010 30 jun 2010 abc 200 365
1 01 jan 2010 31 mar 2010 qqq 600 275
1 01 apr 2010 30 jun 2010 qqq 600 365
1 01 jan 2010 31 mar 2010 xyz 400 275
1 01 apr 2010 30 jun 2010 xyz 400 365
This uses the analytic function last_value() to find the latest non-null value for the value and its corresponding end_date, and then does the necessary subtraction to get the difference between the later periods' and the latest available period's start dates.
N.B. This assumes that there aren't overlapping periods across both tables.

Related

Get the last 4 weeks prior to current week

I have a table that has DATE_VALUE, FISCAL_WEEK, FISCAL_YEAR
DATE_VALUE FISCAL_WEEK FISCAL_YEAR
24-DEC-21 52 2021
25-DEC-21 52 2021
26-DEC-21 52 2021
27-DEC-21 53 2021
28-DEC-21 53 2021
29-DEC-21 53 2021
30-DEC-21 53 2021
31-DEC-21 53 2021
01-JAN-22 53 2021
02-JAN-22 53 2021
03-JAN-22 1 2022
04-JAN-22 1 2022
05-JAN-22 1 2022
06-JAN-22 1 2022
07-JAN-22 1 2022
08-JAN-22 1 2022
09-JAN-22 1 2022
10-JAN-22 2 2022
11-JAN-22 2 2022
12-JAN-22 2 2022
13-JAN-22 2 2022
14-JAN-22 2 2022
The table goes on for the entire FY 2021 & 2022
I want to get the last 4 fiscal weeks (FW) prior to the current week. Let's assume this week is FW20 FY2022, I am able to get this result:
FISCAL_WEEK FISCAL_YEAR
16 2022
17 2022
18 2022
19 2022
The code used to return the above output is:
SELECT
*
FROM
(
WITH t AS (
SELECT
fiscal_week - 1 lastweek,
fiscal_week - 5 week_x,
fiscal_year
FROM
TABLE
WHERE
Trunc(date_value) = Trunc(sysdate)
)
SELECT
DISTINCT fiscal_week,
t.fiscal_year
FROM
TABLE
OUTER JOIN t ON fiscal_week <> week_x
WHERE
to_char(fiscal_week) BETWEEN lastweek - 4
AND lastweek
ORDER BY
fiscal_week
)
But if the current week was FW04 FY2022, the code above is not able to return this desired output.
FISCAL_WEEK FISCAL_YEAR
53 2021
1 2022
2 2022
3 2022
Similarly, if the current was FY03 FY2022, I want the output to be:
FISCAL_WEEK FISCAL_YEAR
52 2021
53 2021
1 2022
2 2022
How do I need to write the code to get this output? Maybe the case statement could work but I'd like to see if there's any other workaround? Any help would be appreciated.
Thank you!
You may put the condition on the date value not the week to get the required output, then use OFFSET 1 to skip the current week and fetch the next 4 rows only. Try the following:
WITH T AS
(
SELECT DISTINCT fiscal_week, fiscal_year
FROM TABLE_NAME
WHERE Trunc(date_value) <= Trunc(SYSDATE)
ORDER BY fiscal_year DESC, fiscal_week DESC
OFFSET 1 ROWS
FETCH NEXT 4 ROWS ONLY
)
SELECT fiscal_week, fiscal_year
FROM T ORDER BY fiscal_year, fiscal_week
See a demo.
Don't use the FISCAL_WEEK and FISCAL_YEAR columns; just use the DATE column and compare it to a range based on the start of the ISO week:
SELECT DISTINCT fiscal_week, fiscal_year
FROM table_name
WHERE "DATE" < TRUNC(SYSDATE, 'IW')
AND "DATE" >= TRUNC(SYSDATE, 'IW') - INTERVAL '28' DAY
ORDER BY fiscal_year, fiscal_week;
Which, for the sample data:
Create Table table_name("DATE", FISCAL_WEEK, FISCAL_YEAR) AS
SELECT DATE '2021-12-24', 52, 2021 FROM DUAL UNION ALL
SELECT DATE '2021-12-25', 52, 2021 FROM DUAL UNION ALL
SELECT DATE '2021-12-26', 52, 2021 FROM DUAL UNION ALL
SELECT DATE '2021-12-27', 53, 2021 FROM DUAL UNION ALL
SELECT DATE '2021-12-28', 53, 2021 FROM DUAL UNION ALL
SELECT DATE '2021-12-29', 53, 2021 FROM DUAL UNION ALL
SELECT DATE '2021-12-30', 53, 2021 FROM DUAL UNION ALL
SELECT DATE '2021-12-31', 53, 2021 FROM DUAL UNION ALL
SELECT DATE '2022-01-01', 53, 2021 FROM DUAL UNION ALL
SELECT DATE '2022-01-02', 53, 2021 FROM DUAL UNION ALL
SELECT DATE '2022-01-03', 1, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-01-04', 1, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-01-05', 1, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-01-06', 1, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-01-07', 1, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-01-08', 1, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-01-09', 1, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-01-10', 2, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-01-11', 2, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-01-12', 2, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-01-13', 2, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-01-14', 2, 2022 FROM DUAL UNION ALL
SELECT DATE '2022-02-14', 6, 2022 FROM DUAL;
If SYSDATE was 2022-01-17, would output:
FISCAL_WEEK
FISCAL_YEAR
52
2021
53
2021
1
2022
2
2022
fiddle

Query Optimization for my code in Oracle SQL

Here is my code:
select
(case when c.yr = 2019 and c.mon = 10 then 'October 2019'
when c.yr = 2019 and c.mon = 11 then 'November 2019'
when c.yr =2019 and c.mon = 12 then 'December 2019' end) as dae
from (
select substr(d,-4,4) as yr, substr(d,1,2) as mon
from
(select '10/11/2019' as d from dual) )c;
`
So I don't want to hard code the dates for the next 5 years, Is there a function that makes this easier.
Here is the Sample Input I want to try
10/11/2019
11/11/2019
12/11/2019
01/11/2020
Expected Output
October 2019
November 2019
December 2019
January 2020
You could use to_date() to turn your string to a date, and then convert it back to a string in the desired format with to_char():
to_char(to_date(d, 'mm/dd/yyyy'), 'Month yyyy')
Demo on DB Fiddle:
with t as (
select '10/11/2019' d from dual
union all select '11/11/2019' from dual
union all select '12/11/2019' from dual
union all select '01/11/2020' from dual
)
select to_char(to_date(d, 'mm/dd/yyyy'), 'Month yyyy') new_dt from t
| NEW_DT |
| :------------- |
| October 2019 |
| November 2019 |
| December 2019 |
| January 2020 |
Use connect by to generate as many dates as you want. Here the gen_dates CTE starts with your start_date and returns a total of 4 months per your example. To increase the number of months to generate, increase the number 4 to a higher number.
with gen_dates(date_in) as (
select add_months('11-OCT-2019', level -1) date_in
from dual
connect by level <= 4
)
select date_in, to_char(date_in, 'Month yyyy') date_out
from gen_dates;
DATE_IN DATE_OUT
--------- --------------
11-OCT-19 October 2019
11-NOV-19 November 2019
11-DEC-19 December 2019
11-JAN-20 January 2020
4 rows selected.

How to create dataset based on specific condition of date?

I have a dataset in the below manner
year mon date org
---- --- --------- ---
2018 mar 21-Mar-18 bb2
2018 mar 19-Mar-18 bbd
2018 feb 17-Feb-18 bbc
2018 feb 15-Feb-18 bba
2018 jan 15-Jan-18 abb
2018 jan 13-Jan-18 abc
and I am trying to get the data repeated in the following manner:
year mon date org
---- --- --------- ---
2018 mar 21-Mar-18 bb2
2018 mar 19-Mar-18 bbd
2018 mar 17-Feb-18 bbc
2018 mar 15-Feb-18 bba
2018 mar 15-Jan-18 abb
2018 mar 13-Jan-18 abc
2018 feb 17-Feb-18 bbc
2018 feb 15-Feb-18 bba
2018 feb 15-Jan-18 abb
2018 feb 13-Jan-18 abc
2018 jan 15-Jan-18 abb
2018 jan 13-Jan-18 abc
Edit:
Sorry about the vague information.
This is a unique requirement, which states as:
" If a user queries for a month, the output should return all the rows of the selected month and the months before it."
So if you look at my existing dataset (this is just dummy data), if I filter for mar I should get 6 rows, for feb 4 rows and 2 rows for jan and so on in a backward manner. So the overall data will consist of 12 rows in a table.
I am working on oracle version 11.2.0.3
any idea or inputs is highly appreciated.
EDIT 2:
Sorry House, I was away for so long. The requirement was scraped so we didn't pursue this route.
However if someone is looking to go in this route, the solution is
self join the table on "org" and Tab_A.column X is >= Tab_B.column X
given that X is a new column( based on year and mon, eg:201803)
To get the latest date for each month/year in the table, you may use max with a group by as follows (table name wasn't given, let's call it myTable):
SELECT year, mon, max(date) FROM myTable GROUP BY year, mon
Then getting your repeated data can be done with a join:
SELECT m2.year, m2.mon, m.date, m.org
FROM myTable AS m
INNER JOIN (SELECT year, mon, max(date) AS maxDate FROM myTable GROUP BY year, mon) AS m2
ON m.date <= m2.maxDate
ORDER BY m2.maxDate DESC, m.date DESC
If you're wanting rows if a user passes in a month and year, this should do the trick:
WITH your_table AS (SELECT 2018 YEAR, 'mar' mon, to_date('21/03/2018', 'dd/mm/yyyy') dt, 'bb2' org FROM dual UNION ALL
SELECT 2018 YEAR, 'mar' mon, to_date('19/03/2018', 'dd/mm/yyyy') dt, 'bbd' org FROM dual UNION ALL
SELECT 2018 YEAR, 'feb' mon, to_date('17/02/2018', 'dd/mm/yyyy') dt, 'bbc' org FROM dual UNION ALL
SELECT 2018 YEAR, 'feb' mon, to_date('15/02/2018', 'dd/mm/yyyy') dt, 'bba' org FROM dual UNION ALL
SELECT 2018 YEAR, 'jan' mon, to_date('15/01/2018', 'dd/mm/yyyy') dt, 'abb' org FROM dual UNION ALL
SELECT 2018 YEAR, 'jan' mon, to_date('13/01/2018', 'dd/mm/yyyy') dt, 'abc' org FROM dual)
-- end of sample data setup
SELECT *
FROM your_table
WHERE to_date(mon||'/'||YEAR, 'mon/yyyy', 'nls_date_language = english') <= to_date(:dt, 'mon/yyyy', 'nls_date_language = english');
:dt = apr/2018
YEAR MON DT ORG
---------- --- ----------- ---
2018 mar 21/03/2018 bb2
2018 mar 19/03/2018 bbd
2018 feb 17/02/2018 bbc
2018 feb 15/02/2018 bba
2018 jan 15/01/2018 abb
2018 jan 13/01/2018 abc
:dt = mar/2018
YEAR MON DT ORG
---------- --- ----------- ---
2018 mar 21/03/2018 bb2
2018 mar 19/03/2018 bbd
2018 feb 17/02/2018 bbc
2018 feb 15/02/2018 bba
2018 jan 15/01/2018 abb
2018 jan 13/01/2018 abc
:dt = feb/2018
YEAR MON DT ORG
---------- --- ----------- ---
2018 feb 17/02/2018 bbc
2018 feb 15/02/2018 bba
2018 jan 15/01/2018 abb
2018 jan 13/01/2018 abc
:dt = jan/2018
YEAR MON DT ORG
---------- --- ----------- ---
2018 jan 15/01/2018 abb
2018 jan 13/01/2018 abc
:dt = dec/2017
no rows selected
You would need to amend the input accordingly; in my query, I've assumed the month being queried for would be in mon/yyyy format; that may or may not be the case.
Also, since we're using mon, I've added in third optional parameter to ensure we're querying with the right date language. The query wouldn't work if the client's language was french, but the data's language is english!
Lastly, this seems like a bad design. You could easily change this table to have just the dt column, and add virtual columns to the table to create the month and year columns (although I wouldn't separate those out; I'd simply do trunc(dt, 'mm') and leave it as an extra date column. Far more flexible, IMO) and index the virtual column(s) accordingly.

How to find next Xth of month after a date

I have two parameters :
a date (Ex : 22/11/2016)
a day number (Ex : 25)
I want to find the next 25th of month after 22/11/2016: 25/11/2016
select trunc(date '2016-11-22', 'month') + 25
from dual;
trunc(date '2016-11-22', 'month') will return the first of the month, the + 25 will then add the desired 25 days.
If the meaning of the second parameter depends on the "comparison" date you can do something like this:
select case
when extract(day from date '2016-11-22') >= 25 then
add_months(trunc(date '2016-11-22', 'month'), 1) + 25
else trunc(date '2016-11-22', 'month') + 25
end as next_date
from dual;
Of course you would replace the hardcoded values for the date and the "number" of days with variables or column values.
This example:
with sample_data (the_date, num_days) as (
select date '2016-11-22', 25 from dual union all
select date ' 2016-11-26', 22 from dual union all
select date ' 2016-11-26', 3 from dual
)
select the_date, num_days,
case
when extract(day from the_date) >= num_days then
add_months(trunc(the_date, 'month'), 1) + num_days - 1
else trunc(the_date, 'month') + num_days - 1
end as next_date
from sample_data;
will return:
THE_DATE | NUM_DAYS | NEXT_DATE
------------+----------+------------
2016-11-22 | 25 | 2016-11-25
2016-11-26 | 22 | 2016-12-22
2016-11-26 | 3 | 2016-12-03
it can solve your problem:
select
(
case
when trunc (:yourdate-trunc(:yourdate,'month'))+1 <:urNum then
trunc(:yourdate,'month')+:urNum-1
else
trunc(last_day(:yourdate))+:urNum
end)
from dual;
You can use
LAST_DAY(<<a date>>) + <<a day number>> + 1
LAST_DAY gives you the last day of give, months (e.i. November, 30th), then add 1 day to get 1st of December plus your day number.
You could use this
WITH tmp AS
(
SELECT TO_DATE('22/11/2016', 'DD/MM/YYYY') date_col FROM DUAL
)
SELECT
CASE WHEN TO_CHAR(date_col,'DD') > '25'
THEN TO_DATE('25' || TO_CHAR(ADD_MONTHS(date_col, 1), '/MM/yyyy'), 'DD/MM/YYYY')
ELSE TO_DATE('25' || TO_CHAR(date_col, '/MM/yyyy'), 'DD/MM/YYYY') END date_col_new
FROM tmp;
If your input (25) is number, you could use TO_CHAR(your_input) instead of '25'
Here's one way:
WITH dates AS (SELECT to_date('30/11/2015', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT to_date('03/11/2015', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT to_date('31/10/2015', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT to_date('29/11/2015', 'dd/mm/yyyy') dt FROM dual UNION ALL
SELECT to_date('31/01/2016', 'dd/mm/yyyy') dt FROM dual),
dom AS (SELECT 25 day_of_month FROM dual UNION ALL
SELECT 31 day_of_month FROM dual UNION ALL
SELECT 30 day_of_month FROM dual UNION ALL
SELECT 03 day_of_month FROM dual UNION ALL
SELECT 01 day_of_month FROM dual),
res AS (SELECT dates.dt starting_dt,
dom.day_of_month,
add_months(TRUNC(dates.dt, 'mm'),
CASE WHEN to_char(dates.dt, 'dd') >= dom.day_of_month
THEN 1
ELSE 0
END) month_of_end_dt
FROM dates
CROSS JOIN dom)
SELECT starting_dt,
day_of_month,
month_of_end_dt + least(day_of_month, to_number(to_char(last_day(month_of_end_dt), 'dd'))) - 1 next_date
FROM res
ORDER BY starting_dt, day_of_month;
STARTING_DATE DAY_OF_MONTH NEXT_DATE
------------- ------------ ----------
31/10/2015 1 01/11/2015
31/10/2015 3 03/11/2015
31/10/2015 25 25/11/2015
31/10/2015 30 30/11/2015
31/10/2015 31 30/11/2015
03/11/2015 1 01/12/2015
03/11/2015 3 03/12/2015
03/11/2015 25 25/11/2015
03/11/2015 30 30/11/2015
03/11/2015 31 30/11/2015
29/11/2015 1 01/12/2015
29/11/2015 3 03/12/2015
29/11/2015 25 25/12/2015
29/11/2015 30 30/11/2015
29/11/2015 31 30/11/2015
30/11/2015 1 01/12/2015
30/11/2015 3 03/12/2015
30/11/2015 25 25/12/2015
30/11/2015 30 30/12/2015
30/11/2015 31 30/11/2015
31/01/2016 1 01/02/2016
31/01/2016 3 03/02/2016
31/01/2016 25 25/02/2016
31/01/2016 30 29/02/2016
31/01/2016 31 29/02/2016
What this does is it first finds out the month that the new date is going to be in by comparing the day you're after with the date being compared with. (ie. if the day of the date you want to get to is already past the day of the starting date, add one to the month, otherwise add nothing).
Once you have that, it's a simple matter of adding the number of days you're trying to get to.
I have assumed that if the month doesn't have the full number of days (eg. February, April, June, September, November) then you'll want whatever the last day of that month is instead.
Therefore, we'll pick whichever is lower - the last day of the month or the day you want to get to. We have to subtract one from that result since we want to include the first of the month in the count.

Generating dates between two dates

I need to generate all dates between two given dates. This works fine as long as there is just one date range. However, if I have multiple date ranges, this solution doesn't work. I have searched here as well as on asktom, but couldn't locate relevant pointers/solution.
I tried both the solutions using all_objects and CONNECT BY ROWNUM, but no luck. Here is the problem statement: sqlfiddle
Input
ID START_DATE END_DATE
101 April, 01 2013 April, 10 2013
102 May, 10 2013 May, 12 2013
Output
ID Dates
101 April, 01 2013
101 April, 02 2013
101 April, 03 2013
101 April, 04 2013
101 April, 05 2013
101 April, 06 2013
101 April, 07 2013
101 April, 08 2013
101 April, 09 2013
101 April, 10 2013
102 May, 10 2013
102 May, 11 2013
102 May, 12 2013
select
A.ID,
A.START_DATE+delta dt
from
t_dates A,
(
select level-1 as delta
from dual
connect by level-1 <= (
select max(end_date - start_date) from t_dates
)
)
where A.START_DATE+delta <= A.end_date
order by 1, 2
Please try:
select
distinct ID,
START_DATE+level-1 DATES
from dual a, TABLE_DATES b
connect by level <= (END_DATE-START_DATE)+1
order by ID;
select g.cycle_dt
from
(select to_date(d,'DD-MM-YYYY') cycle_dt
from dual
model
dimension by (trunc(to_date('30092015', 'DDMMYYYY')) d)
measures (0 y)
rules (
y[for d from trunc(to_date('30092015', 'DDMMYYYY')) to to_date('30102015', 'DDMMYYYY') increment 1]=0
)) g
order by g.cycle_dt;
WITH NUMS AS (
SELECT LEVEL-1 DaysToAdd
FROM DUAL
CONNECT BY LEVEL <= (
SELECT MAX(END_DATE - START_DATE + 1)
FROM HOLIDAY)
)
SELECT START_DATE + DaysToAdd DATE_TIME, DESCRIPTION, IS_SCHOOL_HOLIDAY, UPDATE_BY, CREATE_DATE
FROM HOLIDAY
CROSS JOIN NUMS
WHERE HOLIDAY.END_DATE - HOLIDAY.START_DATE > DaysToAdd
ORDER BY 1, 2;
SELECT TO_DATE('1-JAN-21', 'dd-mm-yy') + ROWNUM - 1
FROM DUAL
CONNECT BY LEVEL <= (TO_DATE('26-APR-22', 'dd-mm-yy') -
TO_DATE('1-JAN-21', 'dd-mm-yy')) + 1;