У меня есть такая таблица:
ID BEGIN END
Если есть перекрывающиеся эпизоды для одного и того же идентификатора (например, 2000-01-01
- 2001-12-31
и 2000-06-01
- 2002-06-31
), я бы хотелстроки, которые должны быть объединены, используя MIN(BEGIN)
, MAX(END)
.
То же самое должно быть сделано, если эпизоды находятся в прямой последовательности (как 2000-01-01
- 2000-06-31
и 2000-07-01
- 2000-12-31
).
Если между эпизодами есть «пропущенные» дни (например, 2000-01-01
- 2000-06-15
и 2000-07-01
- 2000-12-31
), они должны не объединяться.
Как этого достичь?
В настоящее время мой код выглядит следующим образом:
SELECT "ID", MIN("BEGIN"), MAX("END")
FROM ...
GROUP BY "ID"
, но, конечно, это не соответствует последнему условию (не объединять, если есть«пропущенные» дни).
Заранее спасибо!
[править]
Я работаю над решением, к которому я присоединяюсь к таблицес собой.Это улучшение, но оно еще не выполняет свою работу.Я думаю, что другие предложения лучше (но сложнее).Тем не менее, я хотел бы поделиться своими незавершенными работами:
SELECT "ID", LEAST(tab1."BEGIN", tab2."BEGIN"), GREATEST(tab1."END", tab2."END")
FROM <mytable> AS tab1
JOIN <mytable> AS tab2
ON tab1."ID" = tab2."ID"
AND (tab1."BEGIN", tab1."END" + INTERVAL '2 day') OVERLAPS (tab2."BEGIN", tab2."END")
ORDER BY "ID"
[править 2]
Спасибо за вашу помощь!
Я пытался выяснить, как оконные функции и запросы WITH работают уже несколько часов - пока я не понял, что моя база данных работает на PostGreSQL 8.3 (которая не поддерживает ни одну из них).Есть ли способ обойтись без оконных функций и WITH-запросов?
Еще раз спасибо!
[edit 3]
Пример данных:
ID BEGIN END
1;"2000-01-01";"2000-03-31"
1;"2000-04-01";"2000-05-31"
1;"2000-04-15";"2000-07-31"
1;"2000-09-01";"2000-10-31"
2;"2000-02-01";"2000-03-15"
2;"2000-01-15";"2000-03-31"
2;"2000-04-01";"2000-04-15"
3;"2000-06-01";"2000-06-15"
3;"2000-07-01";"2000-07-15"
Пример вывода:
ID BEGIN END
1;"2000-01-01";"2000-07-31"
1;"2000-09-01";"2000-10-31"
2;"2000-01-15";"2000-04-15"
3;"2000-06-01";"2000-06-15"
3;"2000-07-01";"2000-07-15"
[править 4]
одно из возможных решений:
WITH
t1 AS (
SELECT id, begin AS time
FROM "nace-8510-test".checkfkt
UNION ALL
SELECT id, end
FROM "nace-8510-test".checkfkt
),
t2 AS (
SELECT Row_Number() OVER(PARTITION BY id ORDER BY time) AS num, id, time
FROM t1 AS t1_1
),
t3 AS (
SELECT t2_1.num - Row_Number() OVER(PARTITION BY t2_1.id ORDER BY t2_1.time, t2_2.time) num1,
t2_1.id, t2_1.time AS begin, t2_2.time AS end
FROM t2 AS t2_1
INNER JOIN t2 AS t2_2
ON t2_1.id = t2_2.id
AND t2_1.num = t2_2.num - 1
WHERE
EXISTS (
SELECT *
FROM "nace-8510-test".checkfkt AS s
WHERE s.id = t2_1.id
AND (s.begin < t2_2.time AND s.end > t2_1.time)
)
OR t2_1.time = t2_2.time
OR t2_1.time + INTERVAL '1 day' = t2_2.time
)
SELECT id, MIN(begin) AS von, MAX(end) AS bis
FROM t3
GROUP BY id, num1
ORDER BY id
Большое спасибо автору этой статьи: http://blog.developpez.com/sqlpro/p9821/langage-sql-norme/agregation-d-intervalles-en-sql-1/