【问题标题】:Overlapping gaps and islands in a school vacation setup学校假期设置中的重叠间隙和岛屿
【发布时间】:2020-05-24 07:38:31
【问题描述】:

我必须使用这个periods 表:

周期

id  | starts_on  |  ends_on   
----+------------+------------
678 | 2019-12-21 | 2019-12-22
534 | 2019-12-23 | 2020-01-04
679 | 2019-12-28 | 2019-12-29
  9 | 2020-01-01 | 2020-01-01
776 | 2020-01-04 | 2020-01-05
  7 | 2020-01-06 | 2020-01-06
777 | 2020-01-11 | 2020-01-12

它列出了学生不必上学的所有时段。不幸的是,有些时期重叠。这种情况发生在学校假期的周末或公共假期期间(每个假期都有自己的时段行)。

Find rows with adjourning date ranges and accumulate their durationsGaps and islands for school vacations in a country with federal states 的帮助下,我得到了这个查询:

SELECT p.id, p.starts_on, p.ends_on, grp,
      (Max(ends_on) OVER (PARTITION BY grp) - Min(starts_on) OVER (PARTITION BY grp) 
      ) + 1 AS duration, Array_agg(p.id) OVER (PARTITION BY grp) 
FROM (SELECT p.*,
            Count(*) FILTER (WHERE prev_eo < starts_on - INTERVAL '1 day') OVER
                (PARTITION BY 1 
                  ORDER BY starts_on
                ) AS grp 
      FROM (SELECT p.*,
                  lag(ends_on) OVER (PARTITION BY 1 ORDER BY starts_on) AS prev_eo 
            FROM (SELECT p.id, p.starts_on, p.ends_on FROM periods p
            WHERE starts_on > '2019-12-15' AND
                  starts_on < '2020-01-15' ) p 
          ) p 
  ) p;

我得到了什么

结果

id  | starts_on  |  ends_on   | grp | duration |   array_agg   
----+------------+------------+-----+----------+---------------
678 | 2019-12-21 | 2019-12-22 |   0 |       15 | {678,534,679}
534 | 2019-12-23 | 2020-01-04 |   0 |       15 | {678,534,679}
679 | 2019-12-28 | 2019-12-29 |   0 |       15 | {678,534,679}
  9 | 2020-01-01 | 2020-01-01 |   1 |        1 | {9}
776 | 2020-01-04 | 2020-01-05 |   2 |        3 | {776,7}
  7 | 2020-01-06 | 2020-01-06 |   2 |        3 | {776,7}
777 | 2020-01-11 | 2020-01-12 |   3 |        2 | {777}

前三行是grp 0(ID 678、534 和 679)。

我想要什么

但 ID 9、776 和 7 也应该属于 grp。不幸的是,它们重叠。是否有可能得到这样的结果(我不在乎顺序)?

id  | starts_on  |  ends_on   | grp | duration |   array_agg   
----+------------+------------+-----+----------+---------------
678 | 2019-12-21 | 2019-12-22 |   0 |       17 | {678,534,679,9,776,7}
534 | 2019-12-23 | 2020-01-04 |   0 |       17 | {678,534,679,9,776,7}
679 | 2019-12-28 | 2019-12-29 |   0 |       17 | {678,534,679,9,776,7}
  9 | 2020-01-01 | 2020-01-01 |   0 |       17 | {678,534,679,9,776,7}
776 | 2020-01-04 | 2020-01-05 |   0 |       17 | {678,534,679,9,776,7}
  7 | 2020-01-06 | 2020-01-06 |   0 |       17 | {678,534,679,9,776,7}
777 | 2020-01-11 | 2020-01-12 |   1 |        2 | {777}

我想知道总岛屿 (grp 0) 的天数以及它包含的时期 ID。

沙盒:https://rextester.com/SHVL41709

【问题讨论】:

  • 嗨 WIntermeyer。如果您不介意,这里如何计算 grp 和持续时间?
  • grp: Count(*) FILTER (WHERE prev_eo &lt; starts_on - INTERVAL '1 day') OVER (PARTITION BY 1 ORDER BY starts_on ) AS grp
  • 持续时间:(Max(ends_on) OVER (PARTITION BY grp) - Min(starts_on) OVER (PARTITION BY grp) ) + 1 AS duration

标签: sql postgresql gaps-and-islands


【解决方案1】:

这是您其他问题的有趣变体。问题是lag() 只查看前一行以检查重叠。相反,您想查看所有前面的行。

幸运的是,您可以为此使用累积的max()

SELECT p.id, p.starts_on, p.ends_on, grp,
      (Max(ends_on) OVER (PARTITION BY grp) - Min(starts_on) OVER (PARTITION BY grp) 
      ) + 1 AS duration, Array_agg(p.id) OVER (PARTITION BY grp) 
FROM (SELECT p.*,
            Count(*) FILTER (WHERE prev_eo < starts_on - INTERVAL '1 day') OVER
                (PARTITION BY 1 
                  ORDER BY starts_on
                ) AS grp 
      FROM (SELECT p.*,
                  MAX(ends_on) OVER (ORDER BY starts_on ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS prev_eo 
            FROM (SELECT p.id, p.starts_on, p.ends_on 
                  FROM periods p
                  WHERE starts_on > '2019-12-15' AND
                        starts_on < '2020-01-15'
                 ) p 
          ) p 
  ) p;

我不确定PARTITION BY 1 应该做什么,但我没有包含它。

Here 是一名rextester。

预测您的下一个问题。这有一个挑战:如果开始时间相等,那么累积最大值就不稳定。在这种情况下,您要么希望删除重复项,要么使累积最大值的排序保持稳定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-02
    • 2020-05-24
    • 1970-01-01
    • 2023-03-28
    • 2017-04-23
    • 1970-01-01
    • 2019-07-29
    • 1970-01-01
    相关资源
    最近更新 更多