*I have 3 user inputs
I need an oracle sql to output what will be the shift( D or R or E ) on the date 4/2/2022. The pattern will start in 3/14/2022. The output should be R
You can split the pattern and then use arithmetic to find which part of the pattern corresponds to the number of days between your dates.
(Note: you can do it all using simple string functions, which are much faster than regular expressions.)
This will support multiple rows of input:
WITH your_input (startdate, focusdate, pattern) AS (
SELECT DATE '2022-03-14', DATE '2022-04-02', '5D,2R,5E,2R' FROM DUAL UNION ALL
SELECT DATE '2022-03-14', DATE '2022-04-03', '5D,2R,5E,2R' FROM DUAL UNION ALL
SELECT DATE '2022-03-14', DATE '2022-04-04', '5D,2R,5E,2R' FROM DUAL UNION ALL
SELECT DATE '2022-03-14', DATE '2022-04-05', '5D,2R,5E,2R' FROM DUAL
),
bounds (startdate, focusdate, pattern, spos, epos) AS (
-- Find the start and end positions for each term in your pattern.
SELECT startdate,
focusdate,
pattern,
1,
INSTR(pattern, ',', 1)
FROM your_input
UNION ALL
SELECT startdate,
focusdate,
pattern,
epos + 1,
INSTR(pattern, ',', epos + 1)
FROM bounds
WHERE epos > 0
)
SEARCH DEPTH FIRST BY startdate, focusdate, pattern SET order_id,
split_pattern (startdate, focusdate, pattern, pattern_id, pattern_days, pattern_type) AS (
-- Split the pattern into a number of days and the type character using
-- the previously found bounds
SELECT startdate,
focusdate,
pattern,
ROW_NUMBER() OVER (PARTITION BY startdate, focusdate, pattern ORDER BY spos),
TO_NUMBER(
CASE epos
WHEN 0
THEN SUBSTR(pattern, spos, LENGTH(pattern) - spos )
ELSE SUBSTR(pattern, spos, epos - 1 - spos)
END
),
CASE epos
WHEN 0
THEN SUBSTR(pattern, -1, 1)
ELSE SUBSTR(pattern, epos - 1, 1)
END
FROM bounds
),
days (startdate, focusdate, pattern, min_days, max_days, type, total_days) AS (
-- Find the total days across the pattern
SELECT startdate,
focusdate,
pattern,
SUM(pattern_days) OVER (
PARTITION BY startdate, focusdate, pattern
ORDER BY pattern_id
) - pattern_days,
SUM(pattern_days) OVER (
PARTITION BY startdate, focusdate, pattern
ORDER BY pattern_id
) - 1,
pattern_type,
SUM(pattern_days) OVER (
PARTITION BY startdate, focusdate, pattern
)
FROM split_pattern
)
-- Match the part of the pattern containing the date.
SELECT startdate,
focusdate,
pattern,
type
FROM days
WHERE MOD(focusdate - startdate, total_days) BETWEEN min_days AND max_days
Which outputs:
STARTDATE | FOCUSDATE | PATTERN | TYPE |
---|---|---|---|
2022-03-14 00:00:00 | 2022-04-02 00:00:00 | 5D,2R,5E,2R | R |
2022-03-14 00:00:00 | 2022-04-03 00:00:00 | 5D,2R,5E,2R | R |
2022-03-14 00:00:00 | 2022-04-04 00:00:00 | 5D,2R,5E,2R | E |
2022-03-14 00:00:00 | 2022-04-05 00:00:00 | 5D,2R,5E,2R | E |