我想在两个日期时间之间过滤来自单个表的行,并且那些过滤的行应该在一个日期之内,例如
我希望得到之间的所有行 (2015年3月16日6AM)和(2015年3月17日6AM)日期时间(2015年3月17日)日期和 (2015年3月17日6AM)和(2015年3月18日6AM)日期(2015年3月18日)日期等。
这是我的演示表
Id Name LogTime
1 mj 2015-03-16 01:28:03.257
2 mj 2015-03-16 05:28:03.257
3 mj 2015-03-16 06:28:03.257
4 mj 2015-03-16 18:28:03.257
5 mj 2015-03-17 01:28:06.677
6 mj 2015-03-17 06:28:06.677
7 mj 2015-03-17 16:28:07.460
8 mj 2015-03-17 07:28:03.257
9 mj 2015-03-18 01:28:08.193
10 mj 2015-03-18 05:28:03.257
11 mj 2015-03-18 06:28:03.257
12 mj 2015-03-18 18:28:03.257
13 mj 2015-03-19 01:28:06.677
14 mj 2015-03-19 06:28:06.677
15 mj 2015-03-19 16:28:07.460
16 mj 2015-03-19 07:28:03.257
17 mj 2015-03-20 01:28:08.193
18 mj 2015-03-20 05:28:03.257
19 mj 2015-03-20 06:28:03.257
20 mj 2015-03-20 18:28:03.257
下面是我正在使用的查询。
DECLARE @i INT = 1
DECLARE @from DATETIME
, @to DATETIME
WHILE (@i <= 5)
BEGIN
SET @from = CONVERT(DATETIME, CONVERT(VARCHAR(10), DATEADD(D, -@i, '2015-03-20'), 102) + ' 6:00:00')
SET @to = CONVERT(DATETIME, CONVERT(VARCHAR(10), DATEADD(D, -@i + 1, '2015-03-20'), 102) + ' 6:00:00')
SELECT *, @to AS 'FetchedOn'
FROM Biometric
WHERE LogTime BETWEEN @from AND @to
ORDER BY LogTime
SET @i = @i + 1
END
生成以下结果。
Id Name LogTime FetchedOn
14 mj 2015-03-19 06:28:06.677 2015-03-20 06:00:00.000
16 mj 2015-03-19 07:28:03.257 2015-03-20 06:00:00.000
15 mj 2015-03-19 16:28:07.460 2015-03-20 06:00:00.000
17 mj 2015-03-20 01:28:08.193 2015-03-20 06:00:00.000
18 mj 2015-03-20 05:28:03.257 2015-03-20 06:00:00.000
Id Name LogTime FetchedOn
11 mj 2015-03-18 06:28:03.257 2015-03-19 06:00:00.000
12 mj 2015-03-18 18:28:03.257 2015-03-19 06:00:00.000
13 mj 2015-03-19 01:28:06.677 2015-03-19 06:00:00.000
Id Name LogTime FetchedOn
6 mj 2015-03-17 06:28:06.677 2015-03-18 06:00:00.000
8 mj 2015-03-17 07:28:03.257 2015-03-18 06:00:00.000
7 mj 2015-03-17 16:28:07.460 2015-03-18 06:00:00.000
9 mj 2015-03-18 01:28:08.193 2015-03-18 06:00:00.000
10 mj 2015-03-18 05:28:03.257 2015-03-18 06:00:00.000
Id Name LogTime FetchedOn
3 mj 2015-03-16 06:28:03.257 2015-03-17 06:00:00.000
4 mj 2015-03-16 18:28:03.257 2015-03-17 06:00:00.000
5 mj 2015-03-17 01:28:06.677 2015-03-17 06:00:00.000
Id Name LogTime FetchedOn
1 mj 2015-03-16 01:28:03.257 2015-03-16 06:00:00.000
2 mj 2015-03-16 05:28:03.257 2015-03-16 06:00:00.000
现在我希望在不使用循环的情况下获得相同的结果。 我正在使用sql 2014,有没有其他替代解决方案?
答案 0 :(得分:3)
这是一些代码。想法是从测试数据中获得所有可能的不同范围。这就是CTE的回报:
st ed
2015-03-15 06:00:00.000 2015-03-16 06:00:00.000
2015-03-16 06:00:00.000 2015-03-17 06:00:00.000
2015-03-17 06:00:00.000 2015-03-18 06:00:00.000
2015-03-18 06:00:00.000 2015-03-19 06:00:00.000
2015-03-19 06:00:00.000 2015-03-20 06:00:00.000
在此之后,它简单地连接数据落在这些范围之间的条件:
DECLARE @t TABLE(ID INT, D DATETIME)
INSERT INTO @t VALUES
(1 ,'2015-03-16 01:28:03.257'),
(2 ,'2015-03-16 05:28:03.257'),
(3 ,'2015-03-16 06:28:03.257'),
(4 ,'2015-03-16 18:28:03.257'),
(5 ,'2015-03-17 01:28:06.677'),
(6 ,'2015-03-17 06:28:06.677'),
(7 ,'2015-03-17 16:28:07.460'),
(8 ,'2015-03-17 07:28:03.257'),
(9 ,'2015-03-18 01:28:08.193'),
(10 ,'2015-03-18 05:28:03.257'),
(11 ,'2015-03-18 06:28:03.257'),
(12 ,'2015-03-18 18:28:03.257'),
(13 ,'2015-03-19 01:28:06.677'),
(14 ,'2015-03-19 06:28:06.677'),
(15 ,'2015-03-19 16:28:07.460'),
(16 ,'2015-03-19 07:28:03.257'),
(17 ,'2015-03-20 01:28:08.193'),
(18 ,'2015-03-20 05:28:03.257'),
(19 ,'2015-03-20 06:28:03.257'),
(20 ,'2015-03-20 18:28:03.257')
;
WITH cte
AS ( SELECT DISTINCT
DATEADD(HOUR, -18, CAST(CAST(D AS DATE) AS DATETIME)) AS st ,
DATEADD(HOUR, 6, CAST(CAST(D AS DATE) AS DATETIME)) AS ed
FROM @t
)
SELECT t.ID, t.D, c.ed
FROM cte c
JOIN @t t ON t.D BETWEEN c.st AND c.ed
输出:
ID D ed
1 2015-03-16 01:28:03.257 2015-03-16 06:00:00.000
2 2015-03-16 05:28:03.257 2015-03-16 06:00:00.000
3 2015-03-16 06:28:03.257 2015-03-17 06:00:00.000
4 2015-03-16 18:28:03.257 2015-03-17 06:00:00.000
5 2015-03-17 01:28:06.677 2015-03-17 06:00:00.000
6 2015-03-17 06:28:06.677 2015-03-18 06:00:00.000
7 2015-03-17 16:28:07.460 2015-03-18 06:00:00.000
8 2015-03-17 07:28:03.257 2015-03-18 06:00:00.000
9 2015-03-18 01:28:08.193 2015-03-18 06:00:00.000
10 2015-03-18 05:28:03.257 2015-03-18 06:00:00.000
11 2015-03-18 06:28:03.257 2015-03-19 06:00:00.000
12 2015-03-18 18:28:03.257 2015-03-19 06:00:00.000
13 2015-03-19 01:28:06.677 2015-03-19 06:00:00.000
14 2015-03-19 06:28:06.677 2015-03-20 06:00:00.000
15 2015-03-19 16:28:07.460 2015-03-20 06:00:00.000
16 2015-03-19 07:28:03.257 2015-03-20 06:00:00.000
17 2015-03-20 01:28:08.193 2015-03-20 06:00:00.000
18 2015-03-20 05:28:03.257 2015-03-20 06:00:00.000
答案 1 :(得分:2)
您可以根据LogTime字段的时间部分计算FetchedOn:
SELECT B.*, dateadd(day, (iif(cast(LogTime as time) < '06:00:00', 0, 1)), cast(LogTime as date)) + cast('06:00:00' as datetime) as FetchedOn
from Biometric B
ORDER BY FetchedOn DESC, LogTime
<强>更新强>
计算FetchedOn的简单公式,以及为SQL2012 +兼容性添加的datetime
转换。
SELECT B.*, cast(cast(dateadd(hour, +18, LogTime) as date) as datetime) + cast('06:00:00' as datetime) as FetchedOn
from Biometric B
ORDER BY FetchedOn DESC, LogTime
答案 2 :(得分:1)
这是一个适用于SQL Server 2005+的公式:DATEADD(HOUR, 6, CAST(CAST(DATEADD(HOUR, 18, A.LogTime) AS DATE) AS DATETIME))
。我们只是向LogTime添加了18个小时,滥用CAST来截断时间段,然后将6个小时添加到此值。
完整示例(基于原创):
DECLARE @i INT = 5
DECLARE @endDate DATETIME = '2015-03-20 06:00:00.000';
DECLARE @startDate DATETIME = DATEADD(d, -@i, @endDate);
SELECT *
FROM (
SELECT A.Id
, A.LogTime
, FetchedOn = DATEADD(HOUR, 6, CAST(CAST(DATEADD(HOUR, 18, A.LogTime) AS DATE) AS DATETIME))
FROM(VALUES
(1, '2015-03-16 01:28:03.257')
, (2, '2015-03-16 05:28:03.257')
, (3, '2015-03-16 06:28:03.257')
, (4, '2015-03-16 18:28:03.257')
, (5, '2015-03-17 01:28:06.677')
, (6, '2015-03-17 06:28:06.677')
, (7, '2015-03-17 16:28:07.460')
, (8, '2015-03-17 07:28:03.257')
, (9, '2015-03-18 01:28:08.193')
, (10, '2015-03-18 05:28:03.257')
, (11, '2015-03-18 06:28:03.257')
, (12, '2015-03-18 18:28:03.257')
, (13, '2015-03-19 01:28:06.677')
, (14, '2015-03-19 06:28:06.677')
, (15, '2015-03-19 16:28:07.460')
, (16, '2015-03-19 07:28:03.257')
, (17, '2015-03-20 01:28:08.193')
, (18, '2015-03-20 05:28:03.257')
, (19, '2015-03-20 06:28:03.257')
, (20, '2015-03-20 18:28:03.257')
) A (Id, LogTime)
WHERE A.LogTime BETWEEN @startDate AND @endDate
) A
ORDER BY A.FetchedOn DESC, A.LogTime ASC;