2016-12-14 5 views
2

커서를 사용하지 않고이를 수행하는 방법을 찾으려고합니다.이것 대신 커서 대신 사용할 수 있습니까?

나는 약 1300 만 레코드를 합친 데이터 세트가 있습니다. 한 레코드와 다음 레코드 사이의 간격은 다양하지만 모두 5 분에서 20 분 사이입니다. 새로운 데이터 표를 만들 필요가 있지만 하나의 레코드와 다음 레코드 사이의 간격이 적어도 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 분 창에서 가장 낮은 datetime 값을 원하는 것 같습니다. 여기에 파티션이있는 ROW_NUMBER를 사용할 수 있습니다. 아무도 대답을주지 않으면 나는 회의에서 돌아온 후에 무언가를하려고 노력할 것입니다. –

+0

@SeanLange : 고마워! – user3150002

+1

이런 식으로 나는 정말로 내 일이 함께 어울려 2008 년에 벗어나길 바란다. 나는 리드/래그 (Lag/Lag) 대답을 느낀다. 그러나 직장에서 테스트 할 수는 없다. –

답변

1

[vid] 대신 식별자 열을 사용하면 훨씬 쉽습니다. 그런 경우라면 다음 당신이 할 수 있습니다 :

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 만 개 간격이 집계 테이블의 구성 한계에 가까워 지므로 16 밀이 넘으면 변경해야합니다
  • 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

흠 .. 흥미 롭다. 이것을 시험합시다. – user3150002

관련 문제