Skip to content

Instantly share code, notes, and snippets.

@radium226
Created January 13, 2015 14:16
Show Gist options
  • Select an option

  • Save radium226/543dda45d82e9bd4eafd to your computer and use it in GitHub Desktop.

Select an option

Save radium226/543dda45d82e9bd4eafd to your computer and use it in GitHub Desktop.
Example on match intervals presence at the same time.
-- T_INTERVALS:
-- [-----------------------------[ #1 O
-- 08:00 08:30
-- [---------[ #2 X
-- 08:10 08:20
-- [-------------------[ #3 O
-- 08:40 09:00
-- [----------[ #4 X
-- 08:35 08:45
-- [---------[ #5 O
-- 08:55 09:05
-- [---------[ #6 O
-- 09:05 09:15
-- [---------[ #7 O
-- 08:10 08:20
-- [--------------[ #8 X
-- 08:10 08:25
--
-- SQL Query:
-- [--------------[
-- 08:10 08:25
-- [-----[
-- 08:40 08:45
--
CREATE TABLE
t_intervals (
begin_time DATE,
end_time DATE,
category VARCHAR2(5),
code VARCHAR2(5),
flag VARCHAR2(1)
);
INSERT INTO t_intervals(begin_time, end_time, category, code, flag) VALUES (to_date('08:00', 'HH24:MI'), to_date('08:30', 'HH24:MI'), 'A', '#1', 'O');
INSERT INTO t_intervals(begin_time, end_time, category, code, flag) VALUES (to_date('08:10', 'HH24:MI'), to_date('08:20', 'HH24:MI'), 'A', '#2', 'X');
INSERT INTO t_intervals(begin_time, end_time, category, code, flag) VALUES (to_date('08:40', 'HH24:MI'), to_date('09:00', 'HH24:MI'), 'A', '#3', 'O');
INSERT INTO t_intervals(begin_time, end_time, category, code, flag) VALUES (to_date('08:35', 'HH24:MI'), to_date('08:45', 'HH24:MI'), 'A', '#4', 'X');
INSERT INTO t_intervals(begin_time, end_time, category, code, flag) VALUES (to_date('08:55', 'HH24:MI'), to_date('09:05', 'HH24:MI'), 'A', '#5', 'O');
INSERT INTO t_intervals(begin_time, end_time, category, code, flag) VALUES (to_date('09:05', 'HH24:MI'), to_date('09:15', 'HH24:MI'), 'A', '#6', 'O');
INSERT INTO t_intervals(begin_time, end_time, category, code, flag) VALUES (to_date('08:10', 'HH24:MI'), to_date('08:20', 'HH24:MI'), 'A', '#7', 'O');
INSERT INTO t_intervals(begin_time, end_time, category, code, flag) VALUES (to_date('08:10', 'HH24:MI'), to_date('08:25', 'HH24:MI'), 'A', '#8', 'X');
INSERT /*+ APPEND */ INTO t_intervals(begin_time, end_time, category, code, flag) SELECT i.begin_time + 10 / (24 * 60) begin_time, i.end_time + 10 / (24 * 60) end_time, 'B', i.code, i.flag FROM t_intervals i;
COMMIT;
WITH
joined_intervals
AS (
SELECT
i.category,
i.flag,
MIN(i.begin_time) begin_time,
MAX(i.end_time) end_time
FROM
(
SELECT
i.category,
i.flag,
i.begin_time,
i.end_time,
MAX(i.group_1) OVER(PARTITION BY i.category, i.flag ORDER BY i.begin_time ASC) group_2
FROM
(
SELECT
i.category,
i.flag,
i.begin_time,
COALESCE(i.end_time, to_date('99991230', 'YYYYMMDD')) end_time,
CASE
WHEN
(i.begin_time NOT BETWEEN MIN(i.begin_time) OVER(PARTITION BY i.category, i.flag ORDER BY i.begin_time ASC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AND COALESCE(MAX(i.end_time) OVER(PARTITION BY i.category, i.flag ORDER BY i.begin_time ASC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), to_date('99991230', 'YYYYMMDD')))
OR LAG(i.begin_time) OVER(PARTITION BY i.category, i.flag ORDER BY i.begin_time ASC) IS NULL
THEN
row_number() OVER(PARTITION BY i.category, i.flag ORDER BY i.begin_time ASC)
ELSE
-1
END group_1
FROM
t_intervals i
) i
) i
GROUP BY
i.category,
i.flag,
i.group_2
),
moments
AS (
SELECT
m.time,
LEAD(m.time, +1) OVER (PARTITION BY m.category ORDER BY m.time) next_time,
m.category,
m.flag
FROM
(
(
SELECT
i.begin_time time,
i.category,
i.flag
FROM
joined_intervals i
) UNION (
SELECT
i.end_time time,
i.category,
i.flag
FROM
joined_intervals i
)
) m
),
split_intervals
AS (
SELECT
m.time begin_time,
m.next_time end_time,
i.category,
i.flag
FROM
moments m
JOIN
joined_intervals i
ON
m.category = i.category
AND i.begin_time <= m.time AND m.time < i.end_time
),
match_intervals
AS (
SELECT
o.begin_time,
o.end_time,
o.category
FROM
(
SELECT
i.*
FROM
split_intervals i
WHERE
i.flag = 'O'
) o
JOIN
(
SELECT
i.*
FROM
split_intervals i
WHERE
i.flag = 'X'
) x
ON
o.begin_time = x.begin_time AND o.end_time = x.end_time
AND o.category = x.category
)
SELECT
*
FROM
match_intervals;
SELECT
i.category,
MIN(i.begin_time) begin_time,
MAX(i.end_time) end_time
FROM
(
SELECT
i.category,
i.begin_time,
i.end_time,
MAX(i.group_1) OVER(PARTITION BY category ORDER BY i.begin_time ASC) group_2
FROM
(
SELECT
i.category,
i.begin_time,
COALESCE(i.end_time, to_date('99991230', 'YYYYMMDD')) end_time,
CASE
WHEN
(i.begin_time NOT BETWEEN MIN(i.begin_time) OVER(PARTITION BY i.category ORDER BY i.begin_time ASC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AND COALESCE(MAX(i.end_time) OVER(PARTITION BY i.category ORDER BY i.begin_time ASC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), to_date('99991230', 'YYYYMMDD')))
OR LAG(i.begin_time) OVER(PARTITION BY i.category ORDER BY i.begin_time ASC) IS NULL
THEN
row_number() OVER(PARTITION BY i.category ORDER BY i.begin_time ASC)
ELSE
-1
END group_1
FROM
match_intervals i
) i
) i
GROUP BY
i.category,
i.group_2;
DROP TABLE
t_intervals;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment