2013-11-18 14 views
0

я в настоящее время базы данных в следующем форматеразница во времени между значениями строк

ID | DateTime    | PID | TIU 
1 | 2013-11-18 00:15:00 | 1551 | 1005 
2 | 2013-11-18 00:16:03 | 1551 | 1885 
3 | 2013-11-18 00:16:30 | 9110 | 75527 
4 | 2013-11-18 00:22:01 | 1022 | 75 
5 | 2013-11-18 00:22:09 | 1019 | 1311 
6 | 2013-11-18 00:23:52 | 1022 | 89 
7 | 2013-11-18 00:24:19 | 1300 | 44433 
8 | 2013-11-18 00:38:57 | 9445 | 2010 

У меня есть сценарий, где мне нужно, чтобы определить, где имеются пробелы в процессах более чем за 5 минут с помощью DateTime колонки.

Пример того, что я пытаюсь достичь:

ID | DateTime    | PID | TIU 
3 | 2013-11-18 00:16:30 | 9110 | 75527 
4 | 2013-11-18 00:22:01 | 1022 | 75 
7 | 2013-11-18 00:24:50 | 1300 | 44433 
8 | 2013-11-18 00:38:57 | 9445 | 2010 

ID3 последней строка перед вторым зазором 6 минут 1 ID4 является следующей строкой после него.
ID7 - последняя строка перед 14-минутным 7-секундным промежутком, ID8 - следующая доступная запись.

Я пытаюсь сделать это в SQL, однако, если это необходимо, я могу сделать это на C# для обработки.

Я пробовал несколько внутренних соединений, однако таблица имеет более 3 миллионов строк, поэтому производительность сильно страдает.

+0

Хотя решения на основе набора прекрасны и делают SQL столь же мощным, как это, это может потребовать итеративного решения. Тем не менее, он все равно может быть выполнен (и, вероятно, лучше) в SQL. Если вы пытаетесь найти эти пробелы между этой строкой и следующей, курсор и вставка в таблицу temp или CTE, вероятно, то, что вы ищете. –

ответ

0

Это решение КТР, но, как уже было указано, это не всегда может хорошо работать - потому что мы того, чтобы вычислить функции против DateTime столбца, большинство индексов будут бесполезны:

declare @t table (ID int not null,[DateTime] datetime not null, 
        PID int not null,TIU int not null) 
insert into @t(ID,[DateTime],PID,TIU) values 
(1,'2013-11-18 00:15:00',1551,1005 ), 
(2,'2013-11-18 00:16:03',1551,1885 ), 
(3,'2013-11-18 00:16:30',9110,75527), 
(4,'2013-11-18 00:22:01',1022,75 ), 
(5,'2013-11-18 00:22:09',1019,1311 ), 
(6,'2013-11-18 00:23:52',1022,89 ), 
(7,'2013-11-18 00:24:19',1300,44433), 
(8,'2013-11-18 00:38:57',9445,2010 ) 

;With Islands as (
    select ID as MinID,[DateTime],ID as RecID from @t t1 
    where not exists 
     (select * from @t t2 
      where t2.ID < t1.ID and --Or by date, if needed 
        --Use 300 seconds to avoid most transition issues 
      DATEDIFF(second,t2.[DateTime],t1.[DateTime]) < 300 
     ) 
    union all 
    select i.MinID,t2.[DateTime],t2.ID 
    from Islands i 
     inner join 
     @t t2 
      on 
       i.RecID < t2.ID and 
       DATEDIFF(second,i.[DateTime],t2.[DateTime]) < 300 
), Ends as (
    select MinID,MAX(RecID) as MaxID from Islands group by MinID 
) 
select * from @t t 
where exists(select * from Ends e where e.MinID = t.ID or e.MaxID = t.ID) 

Этот также возвращает строку для идентификатора 1, так как эта строка не имеет предшествующей строки в течение 5 минут после нее, но это должно быть достаточно легко исключить при окончательном выборе, если необходимо.

Я предположил, что мы можем использовать ID как прокси-сервер для увеличения даты - что если для двух строк, то ID выше во втором ряду, то DateTime также будет позже.


Islands является рекурсивным CTE. Верхняя половина (якорь) просто выбирает строки, которые не имеют предшествующей строки в течение 5 минут. Мы выбираем ID дважды для этих строк, а также сохраняем DateTime.

В рекурсивной части мы пытаемся найти новую строку из таблицы, которая может быть «добавлена» к существующей строке Islands, основанной на этой новой строке, не более чем на 5 минут позже текущей конечной точки острова.

Как только рекурсия завершена, мы исключаем промежуточные строки, которые производит CTE. Например. для «4» острова, он произвел следующие строки:

4,00:22:01,4 
4,00:22:09,5 
4,00:23:52,6 
4,00:24:19,7 

И все, что мы заботимся о том, что последняя строка, где мы определили «остров» время ID 4 кода 7 - это то, что второй CTE (Ends) находит для нас.

+0

Это выглядит действительно многообещающе, единственный вопрос, который я действительно имею в отношении заявления 'INSERT INTO' для начала. Есть ли способ использовать данные уже в таблице, так как есть 3mil + строки, которые мне нужно проверить. – lethalMango

+0

@lethalMango - да, верхняя часть скрипта - это просто настроить данные, чтобы мой ответ дал полный скрипт, который вы (или любой) можете запустить в SSMS. Чтобы использовать вашу таблицу, вы пропустите верхний раздел и просто замените все ссылки на '@ t' вашей реальной таблицей. –

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