Разделить таблицу на Windows с повторяющимися атрибутами - PullRequest
3 голосов
/ 08 марта 2019

Мое название ужасно, потому что я не знаю, как описать проблему. Я хотел бы редактировать, если кто-то может придумать более описательный заголовок. Надеюсь, мой ввод / желаемый вывод поможет объяснить. Вот некоторые примеры входных данных:

create table #input (
    num varchar(10),
    code varchar(10),
    event_date date
)

insert into #input (num, code, event_date)
values('123456', 'Active', '2007-09-10'),
      ('123456', 'Active', '2010-09-15'),
      ('123456', 'Active', '2010-09-24'),
      ('123456', 'Inactive', '2018-09-17'),
      ('123456', 'Inactive', '2019-01-01'),
      ('123456', 'Active', '2019-02-08')

select *
from #input
order by event_date

Я хочу пометить каждую запись для каждой группы кода num + одним и тем же номером. Тем не менее, я хочу, чтобы периоды времени оставались раздельными. Вот желаемый результат:

create table #result (
    num varchar(10),
    code varchar(10),
    event_date date,
    tag int
)

insert into #result (num, code, event_date, tag)
values('123456', 'Active', '2007-09-10', 1),
      ('123456', 'Active', '2010-09-15', 1),
      ('123456', 'Active', '2010-09-24', 1),
      ('123456', 'Inactive', '2018-09-17', 2),
      ('123456', 'Inactive', '2019-01-01', 2),
      ('123456', 'Active', '2019-02-08', 3)

select *
from #result
order by event_date

Очевидно, что нормальные оконные перегородки такие ...

select *, row_number() over(partition by num, code order by event_date) rn
from #input
order by event_date

... не работает, потому что нет поля для разделения, которое бы разделяло две «активные» группы (две группы, потому что они происходят в течение двух временных периодов). Как бы я достиг желаемого результата? У меня есть предчувствие, что ряд функций lag() и lead() может работать, но я не могу получить ничего значимого.

В качестве альтернативы, как бы я достиг результатов, чтобы категории перекрывались на единицу?

create table #result_new (
    num varchar(10),
    code varchar(10),
    event_date date,
    tag int
)

insert into #result (num, code, event_date, tag)
values('123456', 'Active', '2007-09-10', 1),
      ('123456', 'Active', '2010-09-15', 1),
      ('123456', 'Active', '2010-09-24', 1),
      ('123456', 'Inactive', '2018-09-17', 1),
      ('123456', 'Inactive', '2019-01-01', 2),
      ('123456', 'Active', '2019-02-08', 2)

select *
from #result_new
order by event_date

1 Ответ

3 голосов
/ 08 марта 2019

LAG получает ваш полпути туда, но не весь путь.Вы можете использовать LAG, чтобы проверить значение последней строки и создать (что я назвал) переключатель.Затем вы можете использовать оконную функцию SUM с предложением ROWs BETWEEN, чтобы получить значение для tag:

WITH CTE AS(
      SELECT num,
             code,
             event_date,
             CASE WHEN code = LAG(code) OVER (PARTITION BY num ORDER BY event_date) THEN 0 ELSE 1 END AS Switch
      FROM #input)
SELECT num,
       code,
       event_date,
       SUM(Switch) OVER (PARTITION BY num ORDER BY event_date
                         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS tag
FROM CTE;
...