TSQL: поиск групп записей в последовательности записей - PullRequest
0 голосов
/ 31 августа 2018

Извините за заголовок, если вы нашли его неверным, я действительно не знал, как назвать этот вопрос. Вероятно, есть термин для этого типа запроса / шаблона.

У меня есть последовательность записей, которую нужно упорядочить по дате, записи имеют условие, которое я хотел бы «сгруппировать» по (SomeCondition), чтобы получить самую раннюю дату начала и самую позднюю дату окончания (принимая во внимание значения NULL), но Я не уверен, как выполнить запрос (если это вообще возможно). Исходные записи в таблице выглядят примерно так:

-----------------------------------------------------------
| AbcID | XyzID | StartDate  | EndDate    | SomeCondition |
-----------------------------------------------------------
| 1     | 1     | 2018-01-01 | 2018-03-05 | 1             |
| 2     | 1     | 2018-04-20 | 2018-05-01 | 1             |
| 3     | 1     | 2018-05-02 | 2018-05-15 | 0             |
| 4     | 1     | 2018-06-01 | 2018-07-01 | 1             |
| 5     | 1     | 2018-08-01 | NULL       | 1             |
| 6     | 2     | 2018-01-01 | 2018-06-30 | 1             |
| 7     | 2     | 2018-07-01 | 2018-08-31 | 0             |
-----------------------------------------------------------

Результат, к которому я иду, будет:

-----------------------------------
| XyzID | StartDate  | EndDate    |
-----------------------------------
| 1     | 2018-01-01 | 2018-05-01 |
| 1     | 2018-06-01 | NULL       |
| 2     | 2018-01-01 | 2018-06-30 |
-----------------------------------

Спасибо за любую помощь / понимание, даже если это "невозможно".

1 Ответ

0 голосов
/ 02 сентября 2018

Решение этой проблемы требует от вас ее решения по частям. Вот шаги, которые я использовал для этого:

  1. Определите, когда начинается остров (когда SomeCondition ложно)
  2. Создайте «идентификационный» номер для каждого острова (в пределах каждого XyzID), суммируя число IslandBegin с при рассмотрении записей в AbcID порядке
  3. Определите первый и последний AbcID в каждой комбинации XyzID / IslandNumber, где SomeCondition - истина
  4. Используйте предыдущий шаг в качестве руководства относительно того, что StartDate / EndDate вы должны получить для каждой записи в наборе результатов

Пример данных:

declare @sample_data table
    (
        AbcID int
        , XyzID int
        , StartDate date
        , EndDate date
        , SomeCondition bit
    )

insert into @sample_data
values (1, 1, '2018-01-01', '2018-03-05', 1)             
    , (2, 1, '2018-04-20', '2018-05-01', 1)             
    , (3, 1, '2018-05-02', '2018-05-15', 0)             
    , (4, 1, '2018-06-01', '2018-07-01', 1)             
    , (5, 1, '2018-08-01', NULL, 1)             
    , (6, 2, '2018-01-01', '2018-06-30', 1)             
    , (7, 2, '2018-07-01', '2018-08-31', 0)   

Ответ:

Комментарии в коде показывают, какой шаг выполняет каждая часть CTE .

with island_bgn as
    (
        --Step 1
        select d.AbcID
        , d.XyzID
        , d.StartDate
        , d.EndDate
        , d.SomeCondition
        , case when d.SomeCondition = 0 then 1 else 0 end as IslandBegin
        from @sample_data as d  
    )
    , island_nbr as
    (
        --Step 2
        select b.AbcID
        , b.XyzID
        , b.StartDate
        , b.EndDate
        , b.SomeCondition
        , b.IslandBegin
        , sum(b.IslandBegin) over (partition by b.XyzID order by b.AbcID asc) as IslandNumber
        from island_bgn as b    
    )
    , prelim as
    (
        --Step 3
        select n.XyzID
        , n.IslandNumber
        , min(n.AbcID) as AbcIDMin
        , max(n.AbcID) as AbcIDMax
        from island_nbr as n
        where 1=1
        and n.SomeCondition = 1
        group by n.XyzID
        , n.IslandNumber    
    )
--Step 4
select p.XyzID
, a.StartDate
, b.EndDate
from prelim as p
inner join @sample_data as a on p.AbcIDMin = a.AbcID
inner join @sample_data as b on p.AbcIDMax = b.AbcID
order by p.XyzID
, a.StartDate
, b.EndDate

Результаты:

+-------+------------+------------+
| XyzID | StartDate  | EndDate    |
+-------+------------+------------+
| 1     | 2018-01-01 | 2018-05-01 |
+-------+------------+------------+
| 1     | 2018-06-01 | NULL       |
+-------+------------+------------+
| 2     | 2018-01-01 | 2018-06-30 |
+-------+------------+------------+
...