2016-12-14 1 views
2

私はカーソルを使用せずにこれを達成する方法を見つけようとしています。これはカーソルの代替ですか?

私は約1300万レコードのデータセットを持っています。 1つのレコードと次のレコードの間の間隔は異なりますが、すべて5〜20分です。 新しいデータテーブルを作成する必要がありますが、1レコードと次レコードの間に少なくとも30分のギャップがあるようにデータを選択する必要があります。例えば

私はこれがあれば、:

VID | Datetime 
1 | 2016-01-01 00:00 
1 | 2016-01-01 00:10 
1 | 2016-01-01 00:12 
1 | 2016-01-01 00:25 
2 | 2016-01-01 00:40 
4 | 2016-01-01 01:00 
4 | 2016-01-01 02:13 
6 | 2016-01-01 02:23 
7 | 2016-01-01 02:25 
8 | 2016-01-01 02:49 
9 | 2016-01-01 02:59 
9 | 2016-01-01 03:01 
9 | 2016-01-01 03:09 
9 | 2016-01-01 03:24 
9 | 2016-01-01 04:05 

を新しいテーブルには、次のようになります。

VID | Datetime 
1 | 2016-01-01 00:00 
2 | 2016-01-01 00:40 
4 | 2016-01-01 02:13 
8 | 2016-01-01 02:49 
9 | 2016-01-01 03:24 

私はカーソルではなく、クレイジーだレコードの数百万人のためにこれを行うことができます。私は似たような状況のための変わったアップデートと呼ばれるものの言及を見たことがありますが、それが何であるか分かりません。

現在SQL Server 2014を使用しています。ご協力いただければ幸いです。

+1

は風変わりな更新は、それが正しく動作するための要件のかなり具体的なリストを持っています。それはまた、文書化されていない動作であり、そういう場合もあります。しかし、Jeff Modenはこのトピックについて素晴らしい記事を書いています。 http://www.sqlservercentral.com/articles/T-SQL/68467/欠点は、私はそれがあなたがここで望むものだとは思わないということです。 30分のウィンドウごとに最も低い日時の値が必要なようです。おそらくROW_NUMBERをここにパーティションを使用して使用できます。誰も答えを出さなければ、私は会議から帰ってから何かをしようとします。 –

+0

@SeanLange:ありがとう! – user3150002

+1

このような時代私は本当に自分の仕事が一緒になって2008年になることを願っています。私はリード/ラグの答えを感じていますが、仕事ではテストできません。 –

答えて

1

[vid]の代わりに識別子の列があると、作業が楽になります。 それがそうであったなら、あなたはこれを行うことができます:それはちょうど、各30分間隔で最古の行を取得することが許容される場合はボックスの外側を少し考える

with mycte (id, mydate, keepthis, offset) 
as 
(
    select 
     id, 
     mydate, 
     1 keepthis, 
     0 offset 
    from mytable where id = 1 
    union all 
    select 
     t.id, 
     t.mydate, 
     case when datediff(mi, o.mydate, t.mydate)+o.offset >= 30 then 1 else 0 end keepthis, 
     case when datediff(mi, o.mydate, t.mydate)+o.offset >= 30 then 0 else datediff(mi, o.mydate, t.mydate)+o.offset end 
    from mytable t join mycte o on t.id = o.id+1 
) 

select id,mydate from mycte where keepthis=1 
+0

ROW_NUMBER()を使用してIDを追加できます。レコードは日時の昇順で並べ替えられます。私はこれを試してみる。 – user3150002

+0

^これは残念なことに動作していないようです – user3150002

+0

これは動作しませんか? –

1

を、私は機能するソリューションを持っています。

警告:

  • 私はあなたのデータは限り30年のように戻って行くかもしれない、この時点で想定しました。 1300万回の間隔がタリーテーブルの設定の限界に近づくので、1600万を超える場合は変更する必要があります
  • CTEを一時テーブルとして分割し、インデックスを追加してパフォーマンスを上げる必要があります

:-)データ -

--setup data 
declare @t table (VID int, [Datetime] datetime); 
insert @t values 
     (1, '1986-01-01 00:00'), --very early year 
     (1, '2016-01-01 00:10'), 
     (1, '2016-01-01 00:12'), 
     (1, '2016-01-01 00:25'), 
     (2, '2016-01-01 00:40'), 
     (4, '2016-01-01 01:00'), 
     (4, '2016-01-01 02:13'), 
     (6, '2016-01-01 02:23'), 
     (7, '2016-01-01 02:25'), 
     (8, '2016-01-01 02:49'), 
     (9, '2016-01-01 02:59'), 
     (9, '2016-01-01 03:01'), 
     (9, '2016-01-01 03:09'), 
     (9, '2016-01-01 03:24'), 
     (9, '2016-01-01 04:05'); 
select * from @t order by VID, [Datetime]; 
--select datediff(MI, (select min([Datetime]) from @t), (select max([Datetime]) from @t)); --15778325 records in 30 years - handled by t4 x t4 x t4 in tally generator 

-- Tally generator courtesy of http://www.sqlservercentral.com/blogs/never_say_never/2010/03/19/tally_2D00_table_2D00_cte/ 
-- Tally Table CTE script (SQL 2005+ only) 
-- You can use this to create many different numbers of rows... for example: 
-- You could use a 3 way cross join (t3 x, t3 y, t3 z) instead of just 2 way to generate a different number of rows. 
-- The # of rows this would generate for each is noted in the X3 comment column below. 
-- For most common usage, I find t3 or t4 to be enough, so that is what is coded here. 
-- If you use t3 in ‘Tally’, you can delete t4 and t5. 
; WITH 
    -- Tally table Gen   Tally Rows:  X2    X3 
t1 AS (SELECT 1 N UNION ALL SELECT 1 N), -- 4   , 8 
t2 AS (SELECT 1 N FROM t1 x, t1 y),   -- 16   , 64 
t3 AS (SELECT 1 N FROM t2 x, t2 y),   -- 256   , 4096 
t4 AS (SELECT 1 N FROM t3 x, t3 y),   -- 65536  , 16,777,216 
t5 AS (SELECT 1 N FROM t4 x, t4 y),   -- 4,294,967,296, A lot 
Tally AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) N 
      FROM t4 x, t4 y, t4 z), -- Change the t3's to one of the other numbers above for more/less rows 
--generate time values 
Intervals as (
     select t.N - 1 interval, 
       dateadd(mi, (t.N - 1) * 30, min_date.min_date) interval_start, 
       dateadd(mi, (t.N) * 30, min_date.min_date) next_interval_start 
     from (
       select min([Datetime]) min_date 
       from @t 
       ) min_date 
     join Tally t 
       on t.N <= datediff(MI, (select min([Datetime]) from @t), (select max([Datetime]) from @t))/30 + 1 
), 
--join intervals to data tables 
Intervaled_data as (
     select *, row_number() over (partition by i.interval order by t.[Datetime]) row_num 
     from @t t 
     join Intervals i 
       on t.[Datetime] >= i.interval_start and t.[Datetime] < i.next_interval_start 
) 
select i.VID, i.[Datetime] 
from Intervaled_data i 
where i.row_num = 1 
order by i.VID, i.[Datetime]; 
+0

hmmm ..興味深い。私はこれを試してみましょう。 – user3150002

関連する問題