SQL选择最接近的行到整个小时

时间:2016-12-16 14:17:43

标签: sql sql-server

这是我的SQL Server 2012表(没有固定的插入插件):

DateTime                    Value
2016-12-16 15:08:03.0740000 17,11233139
2016-12-16 15:08:02.0560000 17,8571434
2016-12-16 15:08:00.0410000 17,11233139
2016-12-16 15:07:58.6570000 17,93345451
2016-12-16 15:07:54.9970000 17,11538506
2016-12-16 15:07:53.5910000 17,93345451
2016-12-16 15:06:45.3220000 17,93650818
2016-12-16 15:06:44.1230000 18,65079308
2016-12-16 15:01:09.0470000 20,41208839
2016-12-16 15:01:05.4060000 19,58791161
2016-12-16 15:01:03.3970000 20,41208839
2016-12-16 15:01:00.4070000 19,73138046
2016-12-16 15:00:57.2230000 20,41208839
2016-12-16 15:00:21.0380000 20,51892471
2016-12-16 15:00:19.0270000 21,22100067
2016-12-16 14:42:45.1810000 20,40903473
2016-12-16 14:27:40.0050000 19,59401703
2016-12-16 14:20:40.2510000 18,65995026
2016-12-16 14:19:03.7750000 18,65995026
2016-12-16 14:01:55.0120000 17,93955994
2016-12-16 13:59:07.9490000 17,12454224
2016-12-16 13:59:06.1180000 16,39499474

我希望每小时只有一行,最近的时间是整整一小时。例如。对于小时14,这是与整个小时最接近的值:

2016-12-16 14:01:55.0120000 17,93955994
2016-12-16 13:59:07.9490000 17,12454224

第2行(53秒)与14:00:00之间的差异较小,因此应该采用此行。

我怎么能这样做?感谢

3 个答案:

答案 0 :(得分:3)

使用min窗口功能。

select datetimecol,value 
from (
select t.*,min(datetimecol) over(partition by cast(datetimecol as date),datepart(hour,datetimecol)) mintmstmp
from tablename t
) x
where datetimecol=mintmstmp

编辑1:要获得指定日期特定小时的最接近值,请使用

select top 1 datetimecol,val 
from (select t.*,
      abs(datediff(second,'2016-12-16 14:00:00.0000000',datetimecol)) df
      from tablename t
      ) x
order by df

编辑2:一个选项是使用递归cte生成给定日期的所有小时,并将其连接到现有表,以根据时间差获得最接近的时间戳。

with datetimes as (select cast('2016-12-16 00:00:00.0000000' as datetime2) dt
                   union all
                   select dateadd(hour,1,dt) from datetimes where dt < '2016-12-17 00:00:00.0000000')
select datetimecol,val,dt closest_to_hour
from (
select t.*,dt,
row_number() over(partition by dt order by abs(datediff(second,d.dt,datetimecol))) rn
from tablename t 
join datetimes d on datepart(hour,d.dt) between datepart(hour,datetimecol) and datepart(hour,datetimecol)+1
and cast(d.dt as date) = cast(t.datetimecol as date)
--change this join condition per your specifications
) x
where rn = 1

<强> Sample Demo

答案 1 :(得分:1)

WITH CTE_ClosestToTheHour AS (

SELECT DateTime, Value,

ROW_NUMBER() OVER (PARTITION BY DATEADD(HH, 
                                DATEPART(HH, DateTime),
                                    CAST(CAST(DateTime AS DATE) AS DATETIME)
                                    )

                    ORDER BY 
                            ABS(
                            DATEDIFF(ms, DateTime, 

                                DATEADD(HH, 
                                DATEPART(HH, DateTime),
                                    CAST(CAST(DateTime AS DATE) AS DATETIME)
                                    )
                                    )
                                    )
                            ASC
                    ) AS RN

FROM table
)

SELECT * 
FROM CTE_ClosestToTheHour
WHERE RN = 1
ORDER BY DateTime

答案 2 :(得分:0)

这会使用DATEADD向日期添加30分钟,然后截断到最接近的小时。 ROW_NUMBER函数用于在此日期进行分区,按此与实际日期时间之间的差异排序,然后仅为每个分区选择第一行:

;WITH CTE
AS
(
    SELECT dt, val,
            ROW_NUMBER() OVER 
             (PARTITION BY dateadd(hour, 
                   datediff(hour, 0, dateadd(mi, 30, dt)), 0) 
             ORDER BY 
                ABS(DateDiff(ms, dt,dateadd(hour, 
                  datediff(hour, 0, dateadd(mi, 30, dt)), 0)))) AS RN
    FROM #T
)
SELECT *
FROM CTE
WHERE RN=1