2016-10-11 166 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行,因爲這是輸入時間在結果時間之後的第一行最後一次被選中,下一行假設是第4行的結果時間之後(在「2016-05-03 03:33:00」之後),因此下一行將是第5行。

請求的結果是:

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循環中完成,但是作爲單獨的SELECT,不能當然... – Anton

回答

2

您可以這樣做的一種方法是使用遞歸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; 

編輯:對於多個「符號」,這裏將工作(帶有示例數據)的方法。

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行中的「按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 

編輯

和多版本化符號

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

非常好,完美適用於單個符號,但是我添加了另一個我有多個符號的問題,查看ZLK回答的評論。 如何爲多個符號創建每個符號? – TVC