2017-03-13 68 views
1

假設我在表後的時間戳數據:選擇最接近的時間戳,每30分鐘

Id     Timestamp 
-------------------- ----------------------- 
1     2016-09-19 13:17:24.000 
2576     2016-09-19 13:47:24.000 
4945     2016-09-19 14:17:24.000 
7538     2016-09-19 14:47:24.000 
10016    2016-09-19 15:17:24.000 
10570    2016-09-19 15:24:51.000 
11968    2016-09-19 15:47:55.000 
11990    2016-09-19 15:48:08.000 
13648    2016-09-19 16:18:08.000 
14742    2016-09-19 16:36:55.000 

現在我想從起始日期選擇最接近的時間戳並搜索發現時間戳+ 30分鐘,下一個最接近的時間戳

短例如:

start_date = 2016-09-19 13:00:00.000 
end_date = 2016-09-19 16:00:00.000 
Now it should find record: 
2016-09-19 13:17:24.000 
Now we add 30 minutes to found date, so we will search closest timestamp for 13:47:23.000 and so on until date = 16:00. 

注:應該是接近的近似值,因此它可以小於30分鐘的diff

完整的例子:

start_date = 2016-09-19 13:00:00.000 
end_date = 2016-09-19 16:00:00.000 

Id     Timestamp 
-------------------- ----------------------- 
1     2016-09-19 13:17:24.000 
2576     2016-09-19 13:47:24.000 
4945     2016-09-19 14:17:24.000 
7538     2016-09-19 14:47:24.000 
10016    2016-09-19 15:17:24.000 
11968    2016-09-19 15:47:55.000 

我怎樣才能做到這一點?我寧願避免使用光標,它可以通過

+0

我看不出11968符合您的標準。在第一個時間戳後的00:30:31分。 –

+0

11968是第一個> =上一個(10016)後30分鐘。 – TDP

回答

2

如果IdTimestamp出現在相同的順序使用下面的代碼(沒有遞歸或CTE):

SELECT * 
INTO #TempTable 
FROM (VALUES 
    (1,  CAST('2016-09-19 13:17:24.000' AS DATETIME)), 
    (2576, CAST('2016-09-19 13:47:24.000' AS DATETIME)), 
    (4945, CAST('2016-09-19 14:17:24.000' AS DATETIME)), 
    (7538, CAST('2016-09-19 14:47:24.000' AS DATETIME)), 
    (10016, CAST('2016-09-19 15:17:24.000' AS DATETIME)), 
    (10570, CAST('2016-09-19 15:24:51.000' AS DATETIME)), 
    (11968, CAST('2016-09-19 15:47:55.000' AS DATETIME)), 
    (11990, CAST('2016-09-19 15:48:08.000' AS DATETIME)), 
    (13648, CAST('2016-09-19 16:18:08.000' AS DATETIME)), 
    (14742, CAST('2016-09-19 16:36:55.000' AS DATETIME))) 
    AS T (Id, [Timestamp]) 

DECLARE 
    @StartDate DATETIME = '2016-09-19 13:00:00.000', 
    @EndDate DATETIME = '2016-09-19 16:00:00.000'; 

SELECT MIN(Id) AS Id, MIN([Timestamp]) AS [Timestamp] 
FROM #TempTable 
WHERE [Timestamp] BETWEEN @StartDate AND @EndDate 
GROUP BY 
    CAST([Timestamp] AS DATE), -- day 
    DATEPART(hour, [Timestamp]), -- hour 
    DATEPART(minute, [Timestamp])/30 -- half an hour (0 or 1) 
ORDER BY Id 

如果我們沒有這樣的排序和相同的Timestamp可以出現多次,CTE可以使用:

DECLARE 
    @StartDate DATETIME = '2016-09-19 13:00:00.000', 
    @EndDate DATETIME = '2016-09-19 16:00:00.000'; 

WITH TargetTimestamps AS 
(
    SELECT MIN([Timestamp]) AS MinTimestamp 
    FROM #TempTable 
    WHERE [Timestamp] BETWEEN @StartDate AND @EndDate 
    GROUP BY 
     CAST([Timestamp] AS DATE), -- day 
     DATEPART(hour, [Timestamp]), -- hour 
     DATEPART(minute, [Timestamp])/30 -- half an hour (0 or 1) 
) 
SELECT MIN(Id) AS Id, MinTimestamp 
FROM #TempTable 
JOIN TargetTimestamps ON [Timestamp] = MinTimestamp 
GROUP BY MinTimestamp -- use grouping to avoid duplicates for the same [Timestamp] 
ORDER BY MinTimestamp 
+0

可能我沒有很好地指定要求。您的代碼搜索每30分鐘零件的最小時間戳,例如。它會返回以下值(日期相同):'13:24:00,13:57:00,14:00:00,14:30:00',但我想根據以前的時間戳找到下一個時間戳。因此,在13:57:00之後,它應該搜索13:57:00 + 30分鐘的最近(非最小)時間戳(如14:24或14:33) – mkul

0

您可以在單個查詢中執行此操作。我不是100%確定你實際需要什麼(你的例子似乎在收縮聲明)。但這裏是一般結構:

with x as (
     select min(timestamp) as first_timestamp 
     from t 
     where timestamp >= @start_date 
    ) 
select t.* 
from t join 
    x 
    on t.timestamp >= x.first_timestamp and 
     t.timestamp < dateadd(minute, 30, x.first_timestamp); 
+0

我想他想要在開始之後的第一個,然後是每個下一個至少在先前找到的30分鐘之後。遞歸CTE? – TDP

0

遞推通過

口授

下爲發現時間戳+ 30分鐘最接近時間戳

不幸CTE不允許TOP(1)遞歸部分。解決方法是使用row_number()... = 1

SELECT * 
INTO #TempTable 
FROM (VALUES 
    (1,  CAST('2016-09-19 13:17:24.000' AS DATETIME)), 
    (2576, CAST('2016-09-19 13:47:24.000' AS DATETIME)), 
    (4945, CAST('2016-09-19 14:17:24.000' AS DATETIME)), 
    (7538, CAST('2016-09-19 14:47:24.000' AS DATETIME)), 
    (10016, CAST('2016-09-19 15:17:24.000' AS DATETIME)), 
    (10570, CAST('2016-09-19 15:24:51.000' AS DATETIME)), 
    (11968, CAST('2016-09-19 15:47:55.000' AS DATETIME)), 
    (11990, CAST('2016-09-19 15:48:08.000' AS DATETIME)), 
    (13648, CAST('2016-09-19 16:18:08.000' AS DATETIME)), 
    (14742, CAST('2016-09-19 16:36:55.000' AS DATETIME))) 
    AS T (Id, [Timestamp]) 

DECLARE 
    @StartDate DATETIME = '2016-09-19 13:00:00.000', 
    @EndDate DATETIME = '2016-09-19 16:00:00.000'; 


with found as (
    select top(1) *, r = 1 
    from #TempTable 
    where [Timestamp] between @StartDate and @EndDate 
    order by [Timestamp] 
    union all 
    select t.*, r = cast(row_number() over (partition by f.r order by t.[Timestamp]) as int) 
    from found f 
    join #TempTable t on t.[Timestamp] >= dateadd(minute, 30, f.[Timestamp]) 
     and t.[Timestamp] between @StartDate and @EndDate 
     and f.r=1 
) 
select * 
from found 
where r = 1 
order by [Timestamp] 
相關問題