2017-07-26 2 views
2

SQL Server 2014のテーブルには、それぞれ特定の時間に何百万ものgps座標があります。ただし、登録の間隔は固定されておらず、1秒から2時間までです。私は4分ごとに1つの測定値を保持したいので、他のレコードは削除する必要があります。前と次のレコードとの関係に基づいて削除するレコードを選択する

すべてのレコードをトラバースするWHILEループを試しました。ループ内では、ダブルCROSS APPLYのSELECTステートメントは、4分を超えない他の2つのレコードに収まる場合にのみレコードを返します離れて。しかし、この戦略は遅すぎることが判明しました。

これは、セットベースのソリューションで行うことができますか?または、このクエリをスピードアップする方法はありますか?この場合

Sample data: 
    Id  TimePoint   Lat  Lon 
    1  20170725 13:05:27 12,256 24,123 
    2  20170725 13:10:27 12,254 24,120 
    3  20170725 13:10:29 12,253 24,125 
    4  20170725 13:11:55 12,259 24,127 
    5  20170725 13:11:59 12,255 24,123 
    6  20170725 13:14:28 12,254 24,126 
    7  20170725 13:16:52 12,259 24,121 
    8  20170725 13:20:53 12,257 24,125 

3,4,5を削除すべきレコード -

SELECT * INTO #myTemp FROM gps ORDER BY TimePoint asc 

declare @Id Uniqueidentifier 
declare @d1 varchar(19) 
declare @d2 varchar(19) 
declare @d3 varchar(19) 


While EXISTS (select * from #myTemp) 
BEGIN 
    select top 1 @Id = ID FROM #myTemp order by TimePoint asc 

    SELECT 
     @d1 = convert(varchar(19), a.justbefore, 121), 
     @d2 = convert(varchar(19), b.tijdstip, 121), 
     @d3 = convert(varchar(19), c.justafter, 121) 
    FROM Gps B CROSS APPLY 
     (
      SELECT top 1 TimePoint as justbefore 
      FROM Gps 
      WHERE (B.TimePoint > TimePoint) AND (B.Id = @Id) 
      ORDER by TimePoint desc 
     ) A 
     CROSS APPLY (
      SELECT top 1 TimePoint as justafter 
      FROM Gps 
      WHERE (Datediff(n,A.justbefore,TimePoint) between -4 AND 0) 
        AND (B.TimePoint < TimePoint) 
      ORDER by TimePoint asc 
     ) C 

    print 'ID=' + Cast(@id as varchar(50)) 
       + '/d1=' + @d1 + '/d2=' + @d2 + '/d3=' + @d3     

    DELETE #myTemp where Id = @id 
END 

(下記試験クエリは単に印刷、まだ削除されています)。 7と8の間のギャップが4分を超えているため、レコード7は維持されます。

+0

あなたはいくつかのサンプルデータを投稿できます期待される結果は? –

+2

私はサンプルデータと期待される結果に同意すると、この作業が非常に簡単になります。しかし、ギャップとアイランドの検索をすることをお勧めします。多くの例があります。そのトリックは、レコードを4分単位でグループ化し、それぞれのグループの1番目のレコードを識別できるようにすることです。 – Matt

答えて

0

数字を見ると... 1 & 2滞在(5分間隔)... 3、4、& 5日間... 6泊(2分から4分)... 7 (6からわずか2分)に行くと8回の滞在(6から6分)...

If this is correct, the following will do what you're looking for... 


IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL 
DROP TABLE #TestData; 

CREATE TABLE #TestData (
    Id INT NOT NULL PRIMARY KEY CLUSTERED, 
    TimePoint DATETIME2(0) NOT NULL, 
    Lat DECIMAL(9,3), 
    Lon DECIMAL(9,3) 
    ); 

INSERT #TestData (Id, TimePoint, Lat, Lon) VALUES 
    (1, '20170725 13:05:27', 12.256, 24.123), 
    (2, '20170725 13:10:27', 12.254, 24.120), 
    (3, '20170725 13:10:29', 12.253, 24.125), 
    (4, '20170725 13:11:55', 12.259, 24.127), 
    (5, '20170725 13:11:59', 12.255, 24.123), 
    (6, '20170725 13:14:28', 12.254, 24.126), 
    (7, '20170725 13:16:52', 12.259, 24.121), 
    (8, '20170725 13:20:53', 12.257, 24.125); 

-- SELECT * FROM #TestData td; 

--================================================================================ 

WITH 
    cte_AddLag AS (
     SELECT 
      td.Id, td.TimePoint, td.Lat, td.Lon, 
      MinFromPrev = DATEDIFF(mi, LAG(td.TimePoint, 1) OVER (ORDER BY td.TimePoint), td.TimePoint) 
     FROM 
      #TestData td 
     ), 
    cte_TimeGroup AS (
     SELECT 
      *, 
      TimeGroup = ISNULL(SUM(al.MinFromPrev) OVER (ORDER BY al.TimePoint ROWS UNBOUNDED PRECEDING)/4, 0) 
     FROM 
      cte_AddLag al 
     ) 
SELECT TOP 1 WITH TIES 
    tg.Id, 
    tg.TimePoint, 
    tg.Lat, 
    tg.Lon 
FROM 
    cte_TimeGroup tg 
ORDER BY 
    ROW_NUMBER() OVER (PARTITION BY tg.TimeGroup ORDER BY tg.TimePoint); 

結果...

Id   TimePoint     Lat          Lon 
----------- --------------------------- --------------------------------------- --------------------------------------- 
1   2017-07-25 13:05:27   12.256         24.123 
2   2017-07-25 13:10:27   12.254         24.120 
6   2017-07-25 13:14:28   12.254         24.126 
8   2017-07-25 13:20:53   12.257         24.125 

HTH、ジェイソン

+0

理論上、ポイント7は、できるだけ4分に近いギャップで終わることが目的であるべきです。ポイント7を取り除くことで、ポイント6と8のギャップは6分以上になります。 – Jan

+0

それを行うための効率的な方法ではないでしょう。 –

関連する問題