2017-03-13 9 views
1

最も近いタイムスタンプを選択します。今、私はSTART_DATEから最も近いタイムスタンプを選択し、+ 30分で見つかったタイムスタンプのは、私は、テーブルにタイムスタンプデータを以下していると仮定しましょう、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 

を短い例:

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分未満の差分とすることができる

全例:私はこれを達成するにはどうすればよい

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は、前の1つ(10016)の> 30分後の最初のものです。 – TDP

答えて

2

::私たちは、このような順序を持っていない場合

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%確信しているわけではありません。 IdTimestampが同じ順序で表示された場合は、次のコード(再帰なしまたはCTEではありません)を使用

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] 
関連する問題