Рекурсивный CTE - объединение дат начала и окончания - PullRequest
6 голосов
/ 16 декабря 2011

У меня есть следующая таблица:

row_num customer_status    effective_from_datetime
------- ------------------ -----------------------
1       Active             2011-01-01
2       Active             2011-01-02
3       Active             2011-01-03
4       Suspended          2011-01-04
5       Suspended          2011-01-05
6       Active             2011-01-06

И я пытаюсь добиться следующего результата, при котором последовательные строки с одинаковым статусом объединяются в одну строку с действующим диапазоном от и до даты:

customer_status effective_from_datetime effective_to_datetime
--------------- ----------------------- ---------------------
Active          2011-01-01              2011-01-04
Suspended       2011-01-04              2011-01-06
Active          2011-01-06              NULL

Я могу получить рекурсивный CTE, чтобы вывести правильное значение valid_to_datetime на основе следующей строки, но у меня возникают проблемы при объединении диапазонов.

Код для генерации данных выборки:

CREATE TABLE #temp
(
row_num INT IDENTITY(1,1),
customer_status VARCHAR(10),
effective_from_datetime DATE
)

INSERT INTO #temp
VALUES 
('Active','2011-01-01')
,('Active','2011-01-02')
,('Active','2011-01-03')
,('Suspended','2011-01-04')
,('Suspended','2011-01-05')
,('Active','2011-01-06')

1 Ответ

9 голосов
/ 16 декабря 2011

РЕДАКТИРОВАТЬ SQL обновляется в соответствии с комментарием.

WITH
  group_assigned_data AS
(
  SELECT
    ROW_NUMBER() OVER (PARTITION BY customer_status ORDER BY effective_from_date) AS status_sequence_id,
    ROW_NUMBER() OVER (                             ORDER BY effective_from_date) AS sequence_id,
    customer_status,
    effective_from_date
  FROM
    your_table
)
,
  grouped_data AS
(
  SELECT
    customer_status,
    MIN(effective_from_date)   AS min_effective_from_date,
    MAX(effective_from_date)   AS max_effective_from_date
  FROM
    group_assigned_data
  GROUP BY
    customer_status,
    sequence_id - status_sequence_id
)
SELECT
  [current].customer_status,
  [current].min_effective_from_date       AS effective_from,
  [next].min_effective_from_date          AS effective_to
FROM
  grouped_data   AS [current]
LEFT JOIN
  grouped_data   AS [next]
    ON [current].max_effective_from_date = [next].min_effective_from_date + 1
ORDER BY
  [current].min_effective_from_date

Это не рекурсивно, но, возможно, это хорошо.


Это не касается пробелов в ваших данных. Чтобы справиться с этим, вы можете создать таблицу календаря с каждой соответствующей датой и присоединиться к ней, чтобы заполнить недостающие даты статусом «неизвестно», а затем выполнить запрос для этого. (На самом деле, вы говорите, что это CTE, который используется CTE выше).

В настоящее время ...
- Если строка 2 отсутствует, это не изменит результат
- Если строка 3 отсутствует, end_date первой строки изменится

Различное поведение можно определить, подготовив ваши данные или другими методами. Нам нужно знать бизнес-логику, которая вам нужна.


Если у какой-либо одной даты может быть несколько записей о статусе, вам необходимо определить, какой логике вы хотите следовать. В настоящее время поведение не определено, но вы можете исправить это, просто добавив customer_status к ORDER BY частям ROW_NUMBER ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...