如何在查找重叠 b/w 日期时查找重叠的行
how to find which rows are being overlap while finding overlap b/w the dates
我们如何找到重叠圈 b/w 日期之间的日期。重叠表示开始日期和结束日期在以下示例的相同范围内时第 1 行没有重叠。第 2 行到第 5 行可以被视为一组重叠,因为开始日期和结束与它们自己重叠 第 6 行和第 7 行可以被视为一组重叠,例如。第 6 行和第 7 行 --> 第 7 行的开始日期与第 6 行的结束日期在同一范围内,因此它变成了重叠
一旦找到重叠,就需要找出最小(开始日期)和最大(结束日期)和
想要为每个重叠分配一个唯一的 ID,并且在 S.NO 列中应该显示重叠的行。
下面是I/p和O/p
基于(其中包含对查询的详细解释),您可以更改最后部分以生成重叠行组,然后使用LISTAGG
聚合以获得分隔的sno
值:
SELECT id,
MIN( dt ) AS start_date,
MAX( dt ) AS end_date,
LISTAGG( CASE value WHEN 1 THEN sno END, ',' )
WITHIN GROUP ( ORDER BY dt ) AS snos
FROM (
SELECT sno,
id,
dt,
value,
SUM( start_end ) OVER ( ORDER BY dt ASC, value DESC )
AS grp
FROM (
SELECT sno,
id,
dt,
value,
CASE SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) * value
WHEN 1 THEN 1
WHEN 0 THEN 0
ELSE NULL
END AS start_end
FROM table_name
UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )
)
)
GROUP BY id, grp;
其中,对于示例数据:
CREATE TABLE table_name ( sno, id, start_date, end_date ) AS
SELECT 1, 1, DATE '2020-10-11', DATE '2020-10-11' FROM DUAL UNION ALL
SELECT 2, 1, DATE '2020-11-04', DATE '2020-12-11' FROM DUAL UNION ALL
SELECT 3, 1, DATE '2020-11-05', DATE '2020-11-10' FROM DUAL UNION ALL
SELECT 4, 1, DATE '2020-11-06', DATE '2020-11-10' FROM DUAL UNION ALL
SELECT 5, 1, DATE '2020-11-20', DATE '2020-12-20' FROM DUAL UNION ALL
SELECT 6, 1, DATE '2021-01-01', DATE '2021-01-20' FROM DUAL UNION ALL
SELECT 7, 1, DATE '2021-01-01', DATE '2021-03-25' FROM DUAL;
输出:
ID | START_DATE | END_DATE | SNOS
-: | :------------------ | :------------------ | :------
1 | 2020-10-11 00:00:00 | 2020-10-11 00:00:00 | 1
1 | 2020-11-04 00:00:00 | 2020-12-20 00:00:00 | 2,3,4,5
1 | 2021-01-01 00:00:00 | 2021-03-25 00:00:00 | 6,7
db<>fiddle here
从 Oracle 12c 开始,您可以使用 MATCH_RECOGNIZE
进行更简单的查询:
SELECT id,
MIN( start_date ) AS start_date,
MAX( end_date ) AS end_date,
LISTAGG( sno, ',' ) WITHIN GROUP ( ORDER BY start_date ASC, END_DATE ASC )
AS snos
FROM table_name
MATCH_RECOGNIZE (
PARTITION BY id
ORDER BY start_date ASC, end_date ASC
MEASURES MATCH_NUMBER() AS grp
ALL ROWS PER MATCH
PATTERN ( OVERLAPPING_DATES* LAST_DATE )
DEFINE OVERLAPPING_DATES AS NEXT( start_date ) <= MAX( end_date )
)
GROUP BY id, grp
db<>fiddle here
这是一种间隙岛问题。您可以使用累积最大值来确定是否存在重叠来解决此问题。然后累加和聚合做你想做的事:
select id, min(start_date), max(end_date),
listagg(s_no, ',') within group (order by s_no) as s_nos
from (select t.*,
sum(case when prev_end_date >= start_date then 0 else 1 end) over (partition by id order by s_no) as grp
from (select t.*,
max(end_date) over (
partition by id
order by s_no
rows between unbounded preceding and 1 preceding
) as prev_end_date
from t
) t
) t
group by id, grp;
Here 是一个 db<>fiddle.
我们如何找到重叠圈 b/w 日期之间的日期。重叠表示开始日期和结束日期在以下示例的相同范围内时第 1 行没有重叠。第 2 行到第 5 行可以被视为一组重叠,因为开始日期和结束与它们自己重叠 第 6 行和第 7 行可以被视为一组重叠,例如。第 6 行和第 7 行 --> 第 7 行的开始日期与第 6 行的结束日期在同一范围内,因此它变成了重叠
一旦找到重叠,就需要找出最小(开始日期)和最大(结束日期)和 想要为每个重叠分配一个唯一的 ID,并且在 S.NO 列中应该显示重叠的行。
下面是I/p和O/p
基于LISTAGG
聚合以获得分隔的sno
值:
SELECT id,
MIN( dt ) AS start_date,
MAX( dt ) AS end_date,
LISTAGG( CASE value WHEN 1 THEN sno END, ',' )
WITHIN GROUP ( ORDER BY dt ) AS snos
FROM (
SELECT sno,
id,
dt,
value,
SUM( start_end ) OVER ( ORDER BY dt ASC, value DESC )
AS grp
FROM (
SELECT sno,
id,
dt,
value,
CASE SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) * value
WHEN 1 THEN 1
WHEN 0 THEN 0
ELSE NULL
END AS start_end
FROM table_name
UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )
)
)
GROUP BY id, grp;
其中,对于示例数据:
CREATE TABLE table_name ( sno, id, start_date, end_date ) AS
SELECT 1, 1, DATE '2020-10-11', DATE '2020-10-11' FROM DUAL UNION ALL
SELECT 2, 1, DATE '2020-11-04', DATE '2020-12-11' FROM DUAL UNION ALL
SELECT 3, 1, DATE '2020-11-05', DATE '2020-11-10' FROM DUAL UNION ALL
SELECT 4, 1, DATE '2020-11-06', DATE '2020-11-10' FROM DUAL UNION ALL
SELECT 5, 1, DATE '2020-11-20', DATE '2020-12-20' FROM DUAL UNION ALL
SELECT 6, 1, DATE '2021-01-01', DATE '2021-01-20' FROM DUAL UNION ALL
SELECT 7, 1, DATE '2021-01-01', DATE '2021-03-25' FROM DUAL;
输出:
ID | START_DATE | END_DATE | SNOS -: | :------------------ | :------------------ | :------ 1 | 2020-10-11 00:00:00 | 2020-10-11 00:00:00 | 1 1 | 2020-11-04 00:00:00 | 2020-12-20 00:00:00 | 2,3,4,5 1 | 2021-01-01 00:00:00 | 2021-03-25 00:00:00 | 6,7
db<>fiddle here
从 Oracle 12c 开始,您可以使用 MATCH_RECOGNIZE
进行更简单的查询:
SELECT id,
MIN( start_date ) AS start_date,
MAX( end_date ) AS end_date,
LISTAGG( sno, ',' ) WITHIN GROUP ( ORDER BY start_date ASC, END_DATE ASC )
AS snos
FROM table_name
MATCH_RECOGNIZE (
PARTITION BY id
ORDER BY start_date ASC, end_date ASC
MEASURES MATCH_NUMBER() AS grp
ALL ROWS PER MATCH
PATTERN ( OVERLAPPING_DATES* LAST_DATE )
DEFINE OVERLAPPING_DATES AS NEXT( start_date ) <= MAX( end_date )
)
GROUP BY id, grp
db<>fiddle here
这是一种间隙岛问题。您可以使用累积最大值来确定是否存在重叠来解决此问题。然后累加和聚合做你想做的事:
select id, min(start_date), max(end_date),
listagg(s_no, ',') within group (order by s_no) as s_nos
from (select t.*,
sum(case when prev_end_date >= start_date then 0 else 1 end) over (partition by id order by s_no) as grp
from (select t.*,
max(end_date) over (
partition by id
order by s_no
rows between unbounded preceding and 1 preceding
) as prev_end_date
from t
) t
) t
group by id, grp;
Here 是一个 db<>fiddle.