SQL Server - 需要与输入日期相邻(最接近)的最小和最大日期时间

时间:2013-11-20 17:49:29

标签: sql sql-server sql-server-2005

我在Sql Sever 2005中有一个表:

id  eid  name      datetime   
-- |----|------- |------------------------
 1 | 1  | john   | 2013-11-18 15:30:00.000
 2 | 1  | john   | 2013-11-18 14:10:00.000
 3 | 1  | john   | 2013-11-18 13:30:00.000
 4 | 1  | john   | 2013-11-18 16:00:00.000
 5 | 1  | john   | 2013-11-18 17:00:00.000
 6 | 2  | Richard| 2013-11-18 13:40:00.000
 7 | 2  | Richard| 2013-11-18 16:20:00.000
 8 | 3  | Mandy  | 2013-11-18 20:22:00.000
 9 | 3  | Mandy  | 2013-11-18 20:20:00.000
 10| 4  | Micheal| 2013-11-18 13:00:00.000

输入日期如 - 2013-11-18 15:50:00.000
预期输出:需要与输入日期相邻(最接近)的最小和最大日期时间...
也需要通过eid进行分组。

 id  eid  name      AdjacentMinimumDateTime    AdjacentMaximumDateTime 
-- |----|------- |---------------------------|------------------------
 1 | 1  | john   | 2013-11-18 15:30:00.000   |  2013-11-18 16:00:00.000
 6 | 2  | Richard| 2013-11-18 13:40:00.000   |  2013-11-18 16:20:00.000
 8 | 3  | Mandy  | NULL                      |  2013-11-18 20:20:00.000
 9 | 4  | Micheal| 2013-11-18 13:00:00.000   |  NULL

4 个答案:

答案 0 :(得分:2)

尝试一下:

WITH
BEFORE AS (
  SELECT eid, max(datetime) date FROM t
  WHERE datetime <= '2013-11-18 15:50:00.000'
  GROUP BY eid
),
AFTER AS (
  SELECT eid, min(datetime) date FROM t
  WHERE datetime >= '2013-11-18 15:50:00.000'
  GROUP BY eid
)
SELECT t.eid, t.name, max(b.date) beforeDate, min(a.date) afterDate FROM t
LEFT JOIN BEFORE b ON t.eid = b.eid
LEFT JOIN AFTER a ON t.eid = a.eid
GROUP BY t.eid, t.name
ORDER BY t.eid

或非CTE版本:

SELECT t.eid, t.name, max(b.date) beforeDate, min(a.date) afterDate FROM t
LEFT JOIN (
  SELECT eid, max(datetime) date FROM t
  WHERE datetime <= '2013-11-18 15:50:00.000'
  GROUP BY eid
) b ON t.eid = b.eid
LEFT JOIN (
  SELECT eid, min(datetime) date FROM t
  WHERE datetime >= '2013-11-18 15:50:00.000'
  GROUP BY eid
) a ON t.eid = a.eid
GROUP BY t.eid, t.name
ORDER BY t.eid

我已添加重复日期以测试它是否适用于它们。

输出:

| EID |    NAME |                 BEFOREDATE |                  AFTERDATE |
|-----|---------|----------------------------|----------------------------|
|   1 | john    | November, 18 2013 15:30:00 | November, 18 2013 16:00:00 |
|   2 | Richard | November, 18 2013 13:40:00 | November, 18 2013 16:20:00 |
|   3 | Mandy   |                     (null) | November, 18 2013 20:20:00 |
|   4 | Michael | November, 18 2013 13:00:00 |                     (null) |
|   5 | Mosty   | November, 18 2013 15:00:00 | November, 18 2013 16:00:00 |

小提琴here

答案 1 :(得分:0)

试试这个...

SELECT
    MIN(id) [id],
    eid,
    name,
    (SELECT MAX(datetime) FROM table t1 WHERE t1.datetime < inputdate 
        AND t1.eid = t.eid) [AdjacentMinimumDateTime],
    (SELECT MIN(datetime) FROM table t2 WHERE t2.datetime > inputdate 
        AND t2.eid = t.eid) [AdjacentMaximumDateTime]
FROM table t
GROUP BY t.id, t.Name

答案 2 :(得分:0)

试试我的。它有效

declare @TestTable table (ID int, eid int, Name varchar(10), TestDate datetime)
declare @InputDate datetime = '2013-11-18 15:50:00.000'

insert into @TestTable (ID,eid,Name,TestDate) 
values (1,1,'john', '2013-11-18 15:30:00.000')
      ,(2,1,'john', '2013-11-18 14:10:00.000')
      ,(3,1,'john', '2013-11-18 13:30:00.000')
      ,(4,1,'john', '2013-11-18 16:00:00.000')
      ,(5,1,'john', '2013-11-18 17:00:00.000')
      ,(6,2,'richard', '2013-11-18 13:40:00.000')
      ,(7,2,'richard', '2013-11-18 16:20:00.000')
      ,(8,3,'mandy', '2013-11-18 20:22:00.000')
      ,(9,3,'mandy', '2013-11-18 20:20:00.000')
      ,(10,4,'michael', '2013-11-18 13:00:00.000');


with cte as 
(
select id, eid, name, TestDate, (datediff(s, TestDate, @InputDate)) as DateDiffSeconds
from @TestTable
)

select cte.eid, cte.name, x.testdate as maxunder, y.testdate as minover,         @InputDate as InputDateForComparison
from cte
left join
(
            select eid, testdate
            from cte

        join (  
                    select eid as eidmin, min(DateDiffSeconds) as datematchunder
                    from cte 
                    where DateDiffSeconds >= 0
                    group by eid

                  ) as datematchunder on datematchunder.datematchunder = cte.DateDiffSeconds

 ) x on x.eid = cte.eid

left join 
(
            select eid, testdate
        from cte

        join (  
                    select eid as eidmin, max(DateDiffSeconds) as datematchover
                    from cte
                    where DateDiffSeconds <= 0
                    group by eid

                  ) as datematchover on datematchover.datematchover = cte.DateDiffSeconds

) y on y.eid = cte.eid

group by cte.eid, cte.name, x.testdate, y.testdate;

BAM!

答案 3 :(得分:0)

首先找到前一个和后一个,然后根据需要将它们组合成一个查询:

declare @TestTable table (ID int, eid int, Name varchar(10), TestDate datetime)
declare @InputDate datetime = '2013-11-18 15:50:00.000'

insert into @TestTable (ID,eid,Name,TestDate) 
values (1,1,'john', '2013-11-18 15:30:00.000')
      ,(2,1,'john', '2013-11-18 14:10:00.000')
      ,(3,1,'john', '2013-11-18 13:30:00.000')
      ,(4,1,'john', '2013-11-18 16:00:00.000')
      ,(5,1,'john', '2013-11-18 17:00:00.000')
      ,(6,2,'richard', '2013-11-18 13:40:00.000')
      ,(7,2,'richard', '2013-11-18 16:20:00.000')
      ,(8,3,'mandy', '2013-11-18 20:22:00.000')
      ,(9,3,'mandy', '2013-11-18 20:20:00.000')
      ,(10,4,'michael', '2013-11-18 13:00:00.000');

SELECT *
FROM @TestTable
ORDER BY TestDate

--get the one previous
SELECT TOP 1 *
FROM @TestTable
WHERE TestDate < @InputDate
ORDER BY TestDate desc

--get the one after
SELECT TOP 1 *
FROM @TestTable
WHERE TestDate > @InputDate
ORDER BY TestDate