2017-07-05 11 views
1

私は本当に進行する最良の方法を考えることができない面白いグループケースがあります。私は多くのデータを扱っているので、私は最も効果的なクエリを実行する方法を見つけようとしています。ここでT-SQLグループを決定するためのタイムスタンプの順序付けを検討してください。

は私が順次タイムスタンプが注文したライン&トリップに基づいてグループ分け数を定義できるようにしたいと思い

|Line  |Trip   |Speed  |Timestamp 
==================================================== 
|100  |1    |50 kmh  |2017-06-12 22:34:50 
|100  |1    |55 kmh  |2017-06-12 22:36:44 
|100  |1    |56 kmh  |2017-06-12 22:37:12 
|200  |5    |12 kmh  |2017-06-12 22:40:11 
|200  |5    |18 kmh  |2017-06-12 22:43:13 
|100  |1    |23 kmh  |2017-06-12 22:49:11 
|100  |1    |45 kmh  |2017-06-12 22:53:49 

を持つことができ、データの一例です。だから、基本的には最後に私のような何かを期待:100/1の最後のグループは、最初のレコードに再び合併したがされているので、私はDENSE_RANKまたはROW_NUMBERを使用してどのような方法を見つけることができません

|Line  |Trip   |Speed  |Timestamp   |GroupNumber 
=========================================================================== 
|100  |1    |50 kmh  |2017-06-12 22:34:50 | 1 
|100  |1    |55 kmh  |2017-06-12 22:36:44 | 1 
|100  |1    |56 kmh  |2017-06-12 22:37:12 | 1 
|200  |5    |12 kmh  |2017-06-12 22:40:11 | 2 
|200  |5    |18 kmh  |2017-06-12 22:43:13 | 2 
|100  |1    |23 kmh  |2017-06-12 22:49:11 | 3 
|100  |1    |45 kmh  |2017-06-12 22:53:49 | 3 

をすべきではないので、そこに両方の発生の間に別のグループ(200/5)です。

ご協力いただければ幸いです。 ありがとうございます。

答えて

3

これはギャップと諸島の問題として知られています。

島を特定するには、2つの順位付け関数を使用する必要があります。最初にセット内の行の位置を検索し、次にそのサブセット内の行の位置を見つける2番目の行(Line、Trip)、Soあなたがで終わるでしょう:あなたは

|Line  |Trip   |Speed  |Timestamp    R1  R2 (R1 - R2) 
======================================================================================= 
|100  |1    |50 kmh  |2017-06-12 22:34:50 1  1  0 
|100  |1    |55 kmh  |2017-06-12 22:36:44 2  2  0 
|100  |1    |56 kmh  |2017-06-12 22:37:12 3  3  0 
|200  |5    |12 kmh  |2017-06-12 22:40:11 4  1  3 
|200  |5    |18 kmh  |2017-06-12 22:43:13 5  2  3 
|100  |1    |23 kmh  |2017-06-12 22:49:11 6  4  2 
|100  |1    |45 kmh  |2017-06-12 22:53:49 7  5  2 

最後に各島の一意の識別子を取得し、他のから1を差し引く場合は、今すぐ

SELECT Line, 
     Trip, 
     Speed, 
     Timestamp, 
     R1 = ROW_NUMBER() OVER(ORDER BY Timestamp), 
     R2 = ROW_NUMBER() OVER(PARTITION BY Line, Trip ORDER BY Timestamp) 
FROM dbo.YourTable; 


|Line  |Trip   |Speed  |Timestamp    R1  R2 
========================================================================== 
|100  |1    |50 kmh  |2017-06-12 22:34:50 1  1 
|100  |1    |55 kmh  |2017-06-12 22:36:44 2  2 
|100  |1    |56 kmh  |2017-06-12 22:37:12 3  3 
|200  |5    |12 kmh  |2017-06-12 22:40:11 4  1 <-- starts new sequence for new group 
|200  |5    |18 kmh  |2017-06-12 22:43:13 5  2 
|100  |1    |23 kmh  |2017-06-12 22:49:11 6  4 <-- follows on from where it left off 
|100  |1    |45 kmh  |2017-06-12 22:53:49 7  5 

、あなたは開始時間を取得するには、この一意の識別子を使用することができますグループごとに:

SELECT Line, 
     Trip, 
     Speed, 
     Timestamp, 
     GroupStart = MIN(Timestamp) OVER(PARTITION BY Line, Trip, IslandID) 
FROM ( SELECT Line, 
        Trip, 
        Speed, 
        Timestamp, 
        IslandID = ROW_NUMBER() OVER(ORDER BY Timestamp) - 
           ROW_NUMBER() OVER(PARTITION BY Line, Trip 
                ORDER BY Timestamp) 
      FROM dbo.YourTable 
     ) AS t; 

最後に、グループの開始時刻にDENSE_RANK()を適用すると、整数のランキングが得られます。だからあなたのサンプルデータであなたが得るでしょう:

最初の3行のための
-- SAMPLE DATA 
DECLARE @T TABLE (Line INT, Trip INT, Speed VARCHAR(6), Timestamp DATETIME); 
INSERT @T (Line, Trip, Speed, Timestamp) 
VALUES 
    (100, 1, '50 kmh', '2017-06-12 22:34:50'), 
    (100, 1, '55 kmh', '2017-06-12 22:36:44'), 
    (100, 1, '56 kmh', '2017-06-12 22:37:12'), 
    (200, 5, '12 kmh', '2017-06-12 22:40:11'), 
    (200, 5, '18 kmh', '2017-06-12 22:43:13'), 
    (100, 1, '23 kmh', '2017-06-12 22:49:11'), 
    (100, 1, '45 kmh', '2017-06-12 22:53:49'); 

WITH GroupedData AS 
( SELECT Line, 
      Trip, 
      Speed, 
      Timestamp, 
      GroupStart = MIN(Timestamp) OVER(PARTITION BY Line, Trip, IslandID), 
      IslandID 
    FROM ( SELECT Line, 
         Trip, 
         Speed, 
         Timestamp, 
         IslandID = ROW_NUMBER() OVER(ORDER BY Timestamp) - 
            ROW_NUMBER() OVER(PARTITION BY Line, Trip 
                 ORDER BY Timestamp) 
       FROM @T 
      ) AS t 
) 
SELECT Line, 
     Trip, 
     Speed, 
     Timestamp, 
     GroupNumber = DENSE_RANK() OVER(ORDER BY GroupStart, IslandID) 
FROM GroupedData 
ORDER BY Timestamp; 

OUTPUT

Line Trip Speed Timestamp     GroupNumber 
-------------------------------------------------------------- 
100  1  50 kmh 2017-06-12 22:34:50.000  1 
100  1  55 kmh 2017-06-12 22:36:44.000  1 
100  1  56 kmh 2017-06-12 22:37:12.000  1 
200  5  12 kmh 2017-06-12 22:40:11.000  2 
200  5  18 kmh 2017-06-12 22:43:13.000  2 
100  1  23 kmh 2017-06-12 22:49:11.000  3 
100  1  45 kmh 2017-06-12 22:53:49.000  3 
+1

(R1-R2)は0ではない1である(ただし、明らかにこれはの正しさを変更しません。答え) – etsa

+0

@etsaありがとう。私はそれを訂正し、そのような基本的な算術的なエラーで私の頭を恥でぶら下げました – GarethD

+0

これは完璧です。実際には、DENSE_RANKの余分な部分は必要ありません。最初のROW_NUMBERからROW_NUMBERを差し引くと、私のグループが完全に識別され、それだけで十分です。どうもありがとうございました! – Chris

関連する問題