2011-12-16 3 views
5

У меня есть следующая таблица:Рекурсивный CTE - консолидировать даты начала и окончания

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 

я могу получить рекурсивное ОТВ для вывода правильного effective_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') 
+0

О, и я не хочу использовать курсор или цикл, потому что план заключается в использовании этой логики в представлении. – shakedown7

+0

Что делать, если у вас нет записи о дате? Должно ли это считаться пробелом в последовательности? например предположим, что строки '('Active', '2011-01-02')' не было? –

ответ

8

EDIT 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 

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


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

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

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


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

+0

Perfect - спасибо! – shakedown7

+0

Одна проблема, которую я вижу (что, по-моему, делает решение совершенно другим) - эффективное_то_датное время должно быть равно эффективному_from_datetime следующей строки. – shakedown7

+0

@ shakedown7 - Это ситуация «пробела», о которой я говорил. Если у вас есть пробелы, что самое легкое решение - ЛЕВАЯ ВСТУПЛЕНИЕ в таблицу календаря, чтобы заполнить пробелы. Это приведет к появлению трех типов групп, одна из которых относится к вашим разрывам, и вы можете дать имя или выбрать фильтр после этого. – MatBailie

Смежные вопросы