postgresql:在事件中拆分时间段
postgresql: splitting time period at event
我有一个 table 国家时期。在某些情况下,某些国家/地区属性(例如首都)会在某个时间段内的某个日期发生变化。在这里,我想将 country-period 分成两个新的时期,一个在这个变化之前,一个在这个变化之后。
示例:
Country | start_date | end_date | event_date
A | 1960-01-01 | 1999-12-31 | 1994-07-20
B | 1926-01-01 | 1995-12-31 | NULL
期望的输出:
Country | start_date | end_date | event_date
A | 1960-01-01 | 1994-07-19 | 1994-07-20
A | 1994-07-20 | 1999-12-31 | 1994-07-20
B | 1926-01-01 | 1995-12-31 | NULL
我考虑过从 generate_series 开始:
SELECT country, min(p1) as sdate1, max(p1) as sdate2,
min(p2) as sdate2, min(p2) as edate2
FROM
(SELECT country,
generate_series(start_date, (event_date-interval '1 day'), interval '1 day')::date as p1,
generate_series(event_date, end_date, interval '1 day')::date as p2
FROM table)t
GROUP BY country
但这些方法似乎效率低下且混乱。不幸的是,我在编写函数方面没有任何经验。关于如何解决这个问题的任何想法?
您可以改为 UNION
。这样你就不会生成不必要的行
SELECT country, start_date,
CASE WHEN event_date BETWEEN start_date AND end_date
THEN event_date - 1
ELSE end_date
END AS end_date, event_date
FROM table1
UNION ALL
SELECT country, event_date, end_date, event_date
FROM table1
WHERE event_date BETWEEN start_date AND end_date
ORDER BY country, start_date, end_date, event_date
这是一个SQLFiddle演示
输出:
| country | start_date | end_date | event_date |
|---------|------------|------------|------------|
| A | 1960-01-01 | 1994-07-19 | 1994-07-20 |
| A | 1994-07-20 | 1999-12-31 | 1994-07-20 |
| B | 1926-01-01 | 1995-12-31 | (null) |
我有一个 table 国家时期。在某些情况下,某些国家/地区属性(例如首都)会在某个时间段内的某个日期发生变化。在这里,我想将 country-period 分成两个新的时期,一个在这个变化之前,一个在这个变化之后。
示例:
Country | start_date | end_date | event_date
A | 1960-01-01 | 1999-12-31 | 1994-07-20
B | 1926-01-01 | 1995-12-31 | NULL
期望的输出:
Country | start_date | end_date | event_date
A | 1960-01-01 | 1994-07-19 | 1994-07-20
A | 1994-07-20 | 1999-12-31 | 1994-07-20
B | 1926-01-01 | 1995-12-31 | NULL
我考虑过从 generate_series 开始:
SELECT country, min(p1) as sdate1, max(p1) as sdate2,
min(p2) as sdate2, min(p2) as edate2
FROM
(SELECT country,
generate_series(start_date, (event_date-interval '1 day'), interval '1 day')::date as p1,
generate_series(event_date, end_date, interval '1 day')::date as p2
FROM table)t
GROUP BY country
但这些方法似乎效率低下且混乱。不幸的是,我在编写函数方面没有任何经验。关于如何解决这个问题的任何想法?
您可以改为 UNION
。这样你就不会生成不必要的行
SELECT country, start_date,
CASE WHEN event_date BETWEEN start_date AND end_date
THEN event_date - 1
ELSE end_date
END AS end_date, event_date
FROM table1
UNION ALL
SELECT country, event_date, end_date, event_date
FROM table1
WHERE event_date BETWEEN start_date AND end_date
ORDER BY country, start_date, end_date, event_date
这是一个SQLFiddle演示
输出:
| country | start_date | end_date | event_date | |---------|------------|------------|------------| | A | 1960-01-01 | 1994-07-19 | 1994-07-20 | | A | 1994-07-20 | 1999-12-31 | 1994-07-20 | | B | 1926-01-01 | 1995-12-31 | (null) |