假设我在表格中有以下时间戳数据:
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中选择最接近的时间戳,并搜索找到的时间戳+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分钟差异
完整示例:
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 :(得分:2)
如果Id
和Timestamp
出现在同一订单中,请使用以下代码(不是递归或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
答案 1 :(得分: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);
答案 2 :(得分: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]