2016-06-01 6 views
-2

30分以内のギャップを無視できるようにするために、ギャップとアイランドの検出の標準的な方法を読んでいます。私はパフォーマンスの問題のためにカーソルを使用できません。タイムスタンプ列で30分以上のギャップを検出する

少なくとも30分のギャップがあるたびに、開始と終了で新しい行が必要です。少なくとも30のギャップがない場合、結果はタイムスタンプの最小値と最大値を持つ1つの行になります。少なくとも30の隙間が1つある場合、系列の開始から隙間まで、隙間から最後までの2つの行があります。より多くのギャップがある場合、我々はギャップ間の間隔ごとに行を取得、など

入力:

timestamp 

2015-07-15 15:01:21 
2015-07-15 15:17:44 
2015-07-15 15:17:53 
2015-07-15 15:18:34 
2015-07-15 15:21:41 
2015-07-15 15:58:12 
2015-07-15 15:59:12 
2015-07-15 16:05:12 
2015-07-15 17:02:12 

所望の出力:

from | to 

2015-07-15 15:01:21 | 2015-07-15 15:21:41 
2015-07-15 15:58:12 | 2015-07-15 16:05:12 
2015-07-15 17:02:12 | 2015-07-15 17:02:12 
+1

お望みの結果と一致しません。最初の行の時間の差は、30分ではなく20分です。 – FLICKER

+0

データセットに長すぎるカーソルを試しました。私はまた標準的なギャップと島の方法を試しましたが、30分未満のIGNOREギャップにそれを適応させる方法を理解できませんでした – user3431083

+0

私はあなたの望む出力を全く理解しません。最初の5つのレコードはほんの数分離れています。 15:21:41以降は15:58:12まで大きなギャップがあり、次の大きなギャップは16:05:12の後17:02:12までです。 –

答えて

0
;with cc as (
    select Dt 
    , (select top 1 Dt from #tmp where Dt > ot.Dt order by Dt) as NextDt 
    from #tmp ot 
) 
select Dt AS [FROM], NextDt AS [TO] 
from cc 
where DATEDIFF(minute, Dt, NextDt) >= 30 
order by Dt 

テスト

create table #tmp (Dt datetime) 

insert into #tmp values 
('2015-07-15 15:01:21'), 
('2015-07-15 15:17:44'), 
('2015-07-15 15:17:53'), 
('2015-07-15 15:18:34'), 
('2015-07-15 15:21:41'), 
('2015-07-15 15:58:12'), 
('2015-07-15 15:59:12'), 
('2015-07-15 16:05:12'), 
('2015-07-15 17:02:12') 

結果

FROM       TO 
2015-07-15 15:21:41.000  2015-07-15 15:58:12.000 
2015-07-15 16:05:12.000  2015-07-15 17:02:12.000 

ポストは、あなたの質問に答える場合、答え

+0

ありがとうございましたが、これはカーソルよりも遅くなりました。何か案は? – user3431083

+0

テーブルにいくつのレコードがありますか?私はどのセットベースのクエリもカーソルよりも遅くなるとは思わない。 – FLICKER

+0

100k行約3分で走った。 – user3431083

0

としてマークするには、以下のようなアプローチが、性能は大丈夫であると仮定するとぴったり合うように思われる下さい。私はsys.all_tablesカタログビューを使用して、例のようなログテーブルをシミュレートしました。異なる結果を得るには、最初の引数をdatediffに変更することができます。バッチ内のこの1つは;で終了しなければならないか、またはこの文は、1で始まる必要があります前に、

WITH [Sequenced_Entries] AS 
(
    SELECT 
     row_number() OVER(ORDER BY [modify_date] ASC) AS 'sequence', 
     [modify_date] AS 'event_date' 
    FROM 
     sys.all_objects 
) 
SELECT 
    f.[sequence] AS 'from_event_sequence', 
    f.[event_date] AS 'from_event_date', 
    t.[sequence] AS 'to_event_sequence', 
    t.[event_date] AS 'to_event_date' 
FROM 
    [Sequenced_Entries] AS f 
     INNER JOIN 
    [Sequenced_Entries] AS t 
     ON (f.[sequence] = t.[sequence] - 1) 
WHERE 
    datediff(second, f.[event_date], t.[event_date]) < 30 
ORDER BY 
    f.[sequence] ASC 

は声明を忘れないでください。

+0

ありがとう非常に – user3431083

+0

申し訳ありませんが、私のタイトルは "30分以上のIGNOREギャップ"でなければなりません。私はギャップが欲しい、私は大きなギャップを持っていない時間の間隔が欲しい。私が与えた例を確認してください – user3431083

+0

その場合、 '>'をwhere節の '<'にフリップしてください。これは補完的な答えを与えるでしょう。また、大きさを「30」に変更し、単位を「second」に変更して、要件に正確に一致させる必要があります。 –

0
;with Boundaries as (
    select 
     "timestamp" as Stamp, 
     coalesce(
      case when datediff(second, prev_timestamp, "timestamp") >= 1800 
       then 1 else 0 end, 
      1 
     ) as IsBoundary 
    from 
     T t cross apply (
      select max(t2."timestamp") as prev_timestamp from T t2 
      where t2."timestamp" < t."timestamp" 
     ) as n 
), Blocks as (
    select Stamp, sum(IsBoundary) over (order by Stamp) as BlockNum 
    from Boundaries 
) 
select min(Stamp) as "from", max(Stamp) as "to" 
from Blocks 
group by BlockNum 

あなたが時間差でいくつかの世話をする必要があるので、datediff()だけの間隔境界を数えることを覚えておいてください。私はここで1800秒を使用しています。

SQL Serverのそれ以降のエディションを使用している場合は、ギャップを探すのにlead()/lag()を使用できます。しかし、インナー・ジョイントの代わりに、クロス・アプリケーションの方がはるかに速くなることが期待されます。

あなたのタイトル「30分以上のギャップを見つける」と「30分未満のギャップを無視する」というコメントは、あなたが30のギャップを限定している行を探していると思っていた分。これは、目的の出力に応じて問題を解決する唯一の方法です。 (Test here.)

アナリティクスsum() over (order by...)を使用する代わりに、スカラーサブクエリで簡単に置き換えることができます。

... 
), Blocks as (
    select 
     Stamp, 
     (select sum(b2.IsBoundary) from Boundaries b2 where b2.Stamp <= b.Stamp) as BlockNum 
    from Boundaries b 
) ... 
+0

ありがとうございました – user3431083

+0

はい、私のタイトルがよかったです – user3431083

+0

問題 - 私はエラーが発生しています。 – user3431083

1

共通のテーブル式を使用した簡単なソリューションです。少なくとも1000行ある場合は、カーソルのパフォーマンスと比較してください。

create table #tmp (Dt datetime) 

insert into #tmp values 
('2015-07-15 15:01:21'), 
('2015-07-15 15:17:44'), 
('2015-07-15 15:17:53'), 
('2015-07-15 15:18:34'), 
('2015-07-15 15:21:41'), 
('2015-07-15 15:58:12'), 
('2015-07-15 15:59:12'), 
('2015-07-15 16:05:12'), 
('2015-07-15 17:02:12') 

;with tbl as (
select dt, row_number() over(order by dt) rn 
from #tmp 
) 
select t1.dt [from],t2.dt [to], datediff(minute,t1.dt,t2.dt) gap 
from tbl t1 
inner join tbl t2 on t1.rn+1 = t2.rn 
where datediff(minute,t1.dt,t2.dt) >30 
+0

ありがとうございました – user3431083

+0

ご希望の場合は同意してください。 –

+0

レビューとテストに時間が必要です。私がすべてを見直すとすぐに受け入れます。ありがとうございました – user3431083

関連する問題