取出数据库里最靠近指定时间点的数据解决思路

取出数据库里最靠近指定时间点的数据
本帖最后由 hoodlq 于 2014-09-02 09:13:28 编辑
Microsoft SQL Server 2005
表结构
Date                                       data
2014-09-01  07:58:00         22.5
2014-09-01  08:05:00         23.2
2014-09-01  16:39:00         21.2
2014-09-01  17:10:00         20.0

这是我经过筛选得到的表的一部分(每天每小时采集两次,有时候由于漏采集可能只有一次,时间不定)
要求:取出一个月内每天最靠近早上8点和下午5点的两条数据
            一个月30天的话也就是60条数据
------解决方案--------------------
貌似有点复杂,如下是一个思路
IF OBJECT_ID('#test') IS NOT NULL
DROP TABLE #test
GO

CREATE TABLE #test
(
  Date  DATETIME,
  DATA  DECIMAL(10,1)
)

INSERT INTO #test( Date, DATA ) VALUES('2014-09-01 07:57:00',22.2)
INSERT INTO #test( Date, DATA ) VALUES('2014-09-01 07:58:00',22.5)
INSERT INTO #test( Date, DATA ) VALUES('2014-09-01 08:05:00',23.2)
INSERT INTO #test( Date, DATA ) VALUES('2014-09-01 08:04:00',23.1)
INSERT INTO #test( Date, DATA ) VALUES('2014-09-01 16:39:00',21.2)
INSERT INTO #test( Date, DATA ) VALUES('2014-09-01 17:10:00',20.0)

DECLARE @max7 DATETIME
DECLARE @min8 DATETIME
DECLARE @standard DATETIME
 
--取整8点记录       
SELECT TOP 1 Date FROM #test WHERE CONVERT(VARCHAR(16),Date,20) =CONVERT(VARCHAR(13),'2014-09-01 08:00:00',20) 

--取最大7点记录
SELECT @max7 = MAX(Date)  FROM 
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY Date,DATA ORDER BY DATe) 'ID'   FROM #test WHERE CONVERT(VARCHAR(16),Date,20) < CONVERT(VARCHAR(13),'2014-09-01 08:00:00',20) 
) t GROUP BY ID

--取最小8点记录
SELECT @min8 = MIN(Date) FROM 
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY Date,DATA ORDER BY DATe) 'ID'   FROM #test WHERE CONVERT(VARCHAR(16),Date,20) > CONVERT(VARCHAR(13),'2014-09-01 08:00:00',20) 
) t GROUP BY ID

--获取@max7和@min8中最接近8点的标准时间   min( 
------解决方案--------------------
 {@max7,@min8} - 8 
------解决方案--------------------
)
IF (@min8 - CONVERT(VARCHAR(32),'2014-09-01 08:00:00',20)) < (CONVERT(VARCHAR(32),'2014-09-01 08:00:00',20) - @max7)
SET @standard = @min8
ELSE
SET @standard = @max7

SELECT @max7 'max7',@min8 'min8',@standard 'standard'

------解决方案--------------------

with cte as 
(select * ,ABS(DATEDIFF(ss,am8,mydate)) as mydateam8,
ABS(DATEDIFF(ss,pm5,mydate)) as mydatepm5 from (select mydate,data,dateadd(HH,8,(dateadd(day,DATEDIFF(DAY,'20140901',mydate),'20140901'))) as am8,
dateadd(HH,17,(dateadd(day,DATEDIFF(DAY,'20140901',mydate),'20140901'))) as pm5
 from #tt) as p)
--算出各行对2个时间点的时间间隔。
 select mydate,data from cte 
 where mydateam8=(select MIN(mydateam8) from cte)
 or mydatepm5=(select MIN(mydatepm5) from cte)
------解决方案--------------------
WITH 表1(Date,data) AS (
    SELECT Convert(datetime,'2014-09-01 07:58:00',120),22.5 UNION ALL
    SELECT '2014-09-01 08:05:00',23.2 UNION ALL
    SELECT '2014-09-01 16:39:00',21.2 UNION ALL
    SELECT '2014-09-01 17:10:00',20.0
),
-- 分离日期、时间
t (Date,data,d,t) AS (
SELECT *,
       Convert(varchar(10),Date,120),
       Convert(varchar(10),Date,114)
  FROM 表1
 WHERE Date >= '2014-09-01'
   AND Date <  '2014-10-01'
),
-- 每天按离 08:00 的远近排序
t1 (Date,data,d,n) AS (
SELECT Date,data,d,
       ROW_NUMBER() OVER (PARTITION BY d
                              ORDER BY ABS(datediff(second,t,'08:00:00'))
                         )
  FROM t