在PostgreSQL中查询不同的非重叠范围集

时间:2019-05-28 02:59:42

标签: postgresql range

给出一列重叠和/或不连续的范围:

WITH tbl (active_dates) AS
         (
             VALUES
                    ('["2015-05-21","2018-10-01")'::TSRANGE),
                    ('["2016-08-13","2018-09-01")'::TSRANGE),
                    ('["2019-03-01","2019-05-01")'::TSRANGE)
         )
SELECT *
FROM tbl;

我们如何生成标识所有离散时间段的输出,如下所示:

active_dates
------------
["2015-05-21 00:00:00","2016-08-13 00:00:00")
["2016-08-13 00:00:00","2018-09-01 00:00:00")
["2018-09-01 00:00:00","2018-10-01 00:00:00")
["2019-03-01 00:00:00","2018-05-01 00:00:00")

1 个答案:

答案 0 :(得分:1)

与往常一样,您可以使用窗口功能来做到这一点:

WITH tbl (active_dates) AS
         (
             VALUES
                    ('["2015-05-21","2018-10-01")'::TSRANGE),
                    ('["2016-08-13","2018-09-01")'::TSRANGE),
                    ('["2019-03-01","2019-05-01")'::TSRANGE)
         ),
   /* get all time points where something changes */
   points AS (
       SELECT upper(active_dates) AS p
       FROM tbl
       UNION SELECT lower(active_dates)
       FROM tbl
   ),
   /*
    * Get all date ranges between these time points.
    * The first time range will start with NULL,
    * but that will be excluded in the next CTE anyway.
    */
   inter AS (
      SELECT tsrange(
                lag(p) OVER (ORDER BY p),
                p
             ) i
      FROM points
   )
/*
 * Get all date ranges that are contained
 * in at least one of the intervals.
 */
SELECT DISTINCT i
FROM inter
   CROSS JOIN tbl
WHERE i <@ active_dates
ORDER BY i;