我正在尝试解决类似的问题Find all intersections of all sets of ranges in PostgreSQL
不同之处在于,在此线程中,它获取范围 all 范围重叠的范围,而在我的用例中我可能重叠:
考虑4个范围,例如
[2018-01-01, 2018-01-15]
[2018-01-01, 2018-01-02]
[2018-01-07, 2018-01-20]
[2018-01-12, 2018-01-30]
创建像这样的时间轴
A [==============]
B [=]
C [=============]
D [===============]
我想获取所有发生的重叠,所以:
{ entities: [A, B], period: [2018-01-01, 2018-01-02] }
{ entities: [A, C], period: [2018-01-07, 2018-01-11] }
{ entities: [A, C, D], period: [2018-01-12, 2018-01-15] }
{ entities: [C, D], period: [2018-01-15, 2018-01-20] }
另外一件事,在结果中我需要在同一组中最可能的重叠,这解释了为什么没有A, D
重叠。
我在同一时期内已经有A, C, D
,并且没有只有A, D
重叠的句点,而例如A, C
就有一个。
我设法让其他线程的查询与我的setup / tables一起工作,但我不确定是否理解所有这些,尤其是“所有范围重叠的部分”。
感谢。
答案 0 :(得分:0)
这有点难看,因为它使用递归CTE以及daterange和Postgres Range函数,但我认为它会让你进入大球场:
CREATE TEMP TABLE dr (id CHAR(1), range daterange);
INSERT INTO dr VALUES
('A', '2018-01-01', '2018-01-15'),
('B', '2018-01-01', '2018-01-02'),
('C', '2018-01-07', '2018-01-20'),
('D', '2018-01-12', '2018-01-30');
WITH RECURSIVE recRange AS
(
SELECT id,
range,
CAST(id as varchar(100)) as path,
1 as depth
FROM drrange
UNION ALL
SELECT drrange.id,
drrange.range * recRange.range,
CAST(recrange.path || ',' || drrange.id AS VARCHAR(100)),
recRange.depth + 1
FROM recRange INNER JOIN drrange ON
recRange.range && drrange.range
AND recRange.id < drrange.id
--Prevent cycling (which shouldn't happen with that join)
WHERE depth < 20
),
drrange AS
(
SELECT
id,
daterange(from_date, to_date + 1) as range
FROM dr
)
SELECT path as entities, range as period FROM recRange t1
WHERE depth > 1
-- Keep the range only if it is NOT contained by
--+ any other range that has a deeper depth then it
--+ and has the same ending id (id). This isn't the
--+ best logic and could make false positives, but...
--+ it's in the ballpark
AND NOT range <@ ANY(SELECT range FROM recRange WHERE depth > 1 AND depth > t1.depth AND id = t1.id);
entities | period
----------+-------------------------
A,B | [2018-01-01,2018-01-03)
A,C | [2018-01-07,2018-01-16)
C,D | [2018-01-12,2018-01-21)
A,C,D | [2018-01-12,2018-01-16)