2016-10-11 11 views
8

私はSQL Server 2016で作業していますが、そのクエリのビルド方法を理解できません。SQL Server:行間の日付を比較

のは、私はこのようなテーブルがあるとしましょう:私は、エントリの日時は、最後の選択した結果の日時の後にある行だけを選択したい

ID EntryTime    ResultTime 
1 2016-05-02 13:30:00  2016-05-02 21:50:00 
2 2016-05-02 14:45:00  2016-05-02 22:00:00 
3 2016-05-02 16:30:00  2016-05-02 22:21:00 
4 2016-05-03 01:00:00  2016-05-03 03:33:00 
5 2016-05-03 10:30:00  2016-05-04 07:47:00 
6 2016-05-03 12:30:00  2016-05-03 22:45:00 
7 2016-05-04 11:30:00  2016-05-05 21:30:00 
8 2016-05-04 12:30:00  2016-05-04 22:58:00 
9 2016-05-04 13:30:00  2016-05-04 23:04:00 
10 2016-05-04 13:45:00  2016-05-04 22:59:00 
11 2016-05-04 14:00:00  2016-05-04 22:59:00 
12 2016-05-04 14:15:00  2016-05-04 23:04:00 
13 2016-05-04 17:45:00  2016-05-04 21:47:00 
14 2016-05-05 23:30:00  2016-05-06 03:25:00 
15 2016-05-05 23:45:00  2016-05-06 03:30:00 
16 2016-05-06 00:00:00  2016-05-06 03:32:00 
17 2016-05-06 00:15:00  2016-05-06 03:31:00 
18 2016-05-06 00:30:00  2016-05-06 03:25:00 
19 2016-05-06 00:45:00  2016-05-06 02:50:00 
20 2016-05-06 01:00:00  2016-05-06 03:25:00 

たとえば、1行目の結果時間が「2016-05-02 21:50:00」なので、次の行は4行目になります。これは、入力時刻が結果時間後の最初の行であるためです。次の行が5行目になるように、次の行が4行目の結果時間(「2016-05-03 03:33:00」の後)になると仮定します。

要求された結果は次のとおりです。

ID EntryTime    ResultTime 
1 2016-05-02 13:30:00  2016-05-02 21:50:00 
4 2016-05-03 01:00:00  2016-05-03 03:33:00 
5 2016-05-03 10:30:00  2016-05-04 07:47:00 
7 2016-05-04 11:30:00  2016-05-05 21:30:00 
14 2016-05-05 23:30:00  2016-05-06 03:25:00 
+0

あなたの望む出力は不明です。もっと手の込んだことができます... – Teja

+0

私はあなたが唯一の結果を知っていると思います –

+0

面白いです...間違いなく、WHILEループで実行できますが、確かに... – Anton

答えて

2

これを行う方法の1つは、再帰的なCTEを使用して次の行を取得することです。たとえば、

with cte as (
    select * 
    from myTable 
    where id = 1 
    union all 
    select t.* 
    from myTable t 
    cross join cte 
    where t.id = (
     select id 
     from (
      select id, row_number() over (order by id) rn 
      from myTable 
      where entrytime > cte.resulttime) z 
     where rn = 1) 
    ) 
select * from cte; 

EDIT:複数の「記号」の場合、以下の方法があります(データ例を参照)。

DECLARE @myTable TABLE (Symbol CHAR(3), EntryTime DATETIME, ResultTime DATETIME) 
INSERT @myTable VALUES ('AAA','2016-05-02 13:30:00','2016-05-02 21:50:00') 
,('AAA','2016-05-02 14:45:00','2016-05-02 22:00:00') 
,('AAA','2016-05-02 16:30:00','2016-05-02 22:21:00') 
,('AAA','2016-05-03 01:00:00','2016-05-03 03:33:00') 
,('AAA','2016-05-03 10:30:00','2016-05-04 07:47:00') 
,('AAA','2016-05-03 12:30:00','2016-05-03 22:45:00') 
,('AAA','2016-05-04 11:30:00','2016-05-05 21:30:00') 
,('AAA','2016-05-04 12:30:00','2016-05-04 22:58:00') 
,('AAA','2016-05-04 13:30:00','2016-05-04 23:04:00') 
,('AAA','2016-05-04 13:45:00','2016-05-04 22:59:00') 
,('AAA','2016-05-04 14:00:00','2016-05-04 22:59:00') 
,('AAA','2016-05-04 14:15:00','2016-05-04 23:04:00') 
,('AAA','2016-05-04 17:45:00','2016-05-04 21:47:00') 
,('AAA','2016-05-05 23:30:00','2016-05-06 03:25:00') 
,('AAA','2016-05-05 23:45:00','2016-05-06 03:30:00') 
,('AAA','2016-05-06 00:00:00','2016-05-06 03:32:00') 
,('AAA','2016-05-06 00:15:00','2016-05-06 03:31:00') 
,('AAA','2016-05-06 00:30:00','2016-05-06 03:25:00') 
,('AAA','2016-05-06 00:45:00','2016-05-06 02:50:00') 
,('AAA','2016-05-06 01:00:00','2016-05-06 03:25:00') 
,('BBB','2016-05-02 01:00:00','2016-05-02 03:01:00') 
,('BBB','2016-05-02 02:00:00','2016-05-02 03:05:00') 
,('BBB','2016-05-02 03:00:00','2016-05-02 03:40:00') 
,('BBB','2016-05-02 04:00:00','2016-05-02 04:01:00') 
,('BBB','2016-05-02 05:00:00','2016-05-03 07:00:00') 
,('BBB','2016-05-02 06:00:00','2016-05-02 07:00:00') 
,('BBB','2016-05-03 06:00:00','2016-05-03 07:05:00') 
,('BBB','2016-05-04 06:01:00','2016-05-04 07:08:00') 
,('BBB','2016-05-04 06:07:00','2016-05-04 07:52:00') 
,('BBB','2016-05-05 06:00:00','2016-05-05 07:49:00') 
,('CCC','2016-05-05 06:00:00','2016-05-05 07:04:00') 
,('CCC','2016-05-05 06:05:00','2016-05-05 06:55:00') 
,('CCC','2016-05-05 07:00:00','2016-05-05 07:10:00') 
,('CCC','2016-05-05 07:06:00','2016-05-05 08:05:00') 
,('CCC','2016-05-05 08:00:00','2016-05-05 08:15:00') 
,('CCC','2016-05-05 08:09:00','2016-05-05 09:00:00'); 

WITH myTable AS (
    SELECT Symbol, EntryTime, ResultTime, ROW_NUMBER() OVER (PARTITION BY Symbol ORDER BY EntryTime) RN 
    FROM @myTable) 
, CTE AS (
    SELECT * 
    FROM myTable 
    WHERE RN = 1 
    UNION ALL 
    SELECT T.* 
    FROM CTE 
    CROSS APPLY (
     SELECT Symbol, EntryTime, ResultTime, RN 
     FROM (
      SELECT *, ROW_NUMBER() OVER (ORDER BY EntryTime) RN2 
      FROM myTable 
      WHERE Symbol = CTE.Symbol 
      AND EntryTime > CTE.ResultTime) Z 
     WHERE RN2 = 1) T 
    ) 
SELECT Symbol, EntryTime, ResultTime--, RN [ID?] 
FROM CTE 
ORDER BY Symbol; 
+0

+1再帰的なCTEでそれを行う方法を示していますが、各行を一度見ている単純なカーソルは自己結合よりも効率的です。 –

+0

ゼロ値のMAXRECURSIONを指定する必要があります。デフォルトは100です。 – Anton

+0

完璧な回答、迅速かつ効率的です。私は、12行目の「order by id」を「EntryTimeによる注文」に変更しました。なぜなら、IDは常にエントリ時間順ではないからです。 **しかし別の問題が**あります。この表で私は50種類のシンボルを持っていますので、最初のシンボルで動作させました。どのシンボルを50シンボルすべてで実行することができますか(各シンボルは最初のエントリ時間からやり直す必要があります) – TVC

1

あなたは、このクエリを使用することができます。

select * 
from @t t1 
where not exists (
    select 1 
    from @t t2 
    where t2.id < t1.id and t2.resultDate > t1.entryDate 
) 
+0

答えをありがとうが、それはかなり良いではありません。それが選択されていなくても、テーブル内の最後の結果時間を考慮に入れます。 – TVC

+0

たとえば、ある行の結果の時間が10:00:00で、次の行の入力時間が9:00:00で、結果の時間が11:00の場合、その行をスキップし、結果の時間を使用しないと仮定しますエントリー時刻が最後の結果時刻より前であるためです。あなたの答えは、今度は11:00:00以降の次の入力時刻を探し、10:00:00以降ではないと考えています。 – TVC

1

私は時々、カーソルが答え

CREATE FUNCTION getSelected 
( 
) 
RETURNS @res TABLE 
(
    id int, EntryTime DATETIME, ResultTime DATETIME 
) 
AS 
BEGIN 
    declare @idC int; 
    declare @ResultTimeC DATETIME; 
    declare @EntryTimeC DATETIME; 
    declare @lastNextDate DATETIME; 

    DECLARE Iterator CURSOR LOCAL FAST_FORWARD 
    FOR SELECT id, EntryTime, ResultTime FROM dbo.tt1 order by EntryTime, id 
    OPEN Iterator 
    WHILE 1=1 BEGIN 
     FETCH NEXT FROM Iterator INTO @idC, @EntryTimeC, @ResultTimeC 
     IF @@FETCH_STATUS < 0 BREAK 

     if(@lastNextDate is null or @lastNextDate < @EntryTimeC) begin 
      set @lastNextDate = @ResultTimeC; 
      insert into @res (id, EntryTime, ResultTime) values (@idC, @EntryTimeC, @ResultTimeC); 
     end;    
    END 
    CLOSE Iterator 
    DEALLOCATE Iterator; 

    RETURN 
END 

EDIT

そして、複数のシンボルバージョン

だと思います
CREATE FUNCTION getSelected2 
( 
) 
RETURNS @res TABLE 
(
    id int, EntryTime DATETIME, ResultTime DATETIME, Symbol char(3) 
) 
AS 
BEGIN 
    declare @idC int; 
    declare @ResultTimeC DATETIME; 
    declare @EntryTimeC DATETIME; 
    declare @SymbolC char(3); 
    declare @lastNextDate DATETIME; 
    declare @lastSymbol char(3); 

    DECLARE Iterator CURSOR FAST_FORWARD 
    FOR SELECT id, EntryTime, ResultTime, Symbol FROM dbo.tt2 order by Symbol, EntryTime, id 
    OPEN Iterator 
    WHILE 1=1 BEGIN 
     FETCH NEXT FROM Iterator INTO @idC, @EntryTimeC, @ResultTimeC, @SymbolC 
     IF @@FETCH_STATUS < 0 BREAK 

     if(@lastSymbol is null or @lastSymbol <> @SymbolC) begin 
      set @lastSymbol = @SymbolC; 
      set @lastNextDate = null; 
     end; 
     if(@lastNextDate is null or @lastNextDate < @EntryTimeC) begin 
      set @lastNextDate = @ResultTimeC; 
      insert into @res (id, EntryTime, ResultTime, Symbol) values (@idC, @EntryTimeC, @ResultTimeC, @SymbolC); 
     end;    
    END 
    CLOSE Iterator 
    DEALLOCATE Iterator; 

    RETURN 
END 
+0

この機能はどのように実行できますか? – TVC

+0

SELECT * FROM getSelected() –

+0

非常にいいです、単一のSymbolにはうってつけですが、私は複数のシンボルに対して別の問題を追加しています。 どのように最初から始まる複数のSymbolに対して行うことができますか? – TVC