您可以使用TIMEDIFF 和TIME_TO_SEC 方法获取与其他日期“最近”的日期:
SELECT
d
FROM
test
ORDER BY
ABS(TIME_TO_SEC(TIMEDIFF(d, "2015-10-23 19:00:00")))
LIMIT
0,1 ;
http://sqlfiddle.com/#!9/5b67f/2
要获得关闭日期每天和可用条目,您需要扩展此查询,因此它不会与固定日期比较,而是“每天早上 5 点”:
要实现这一点:
- 计算每个条目与其5 AM 日期的最小偏移量
- 按
DATE(d)分组
-
现在是关键点:我们不选择可能由于分组而出错的
date(或min(date))*(注意在帖子末尾),而是使用我们的日期定位加上(或减去)偏移量(由于与min() 聚合一起分组,这是正确)
在示例中,DATE_ADD(DATE(d), INTERVAL 19 HOUR) 用于确定当前行的7 pm。对于5 am,它将是DATE_ADD(DATE(d), INTERVAL 5 HOUR):
(我在查询中留下了调试用的列,可以去掉。你只需要actualDate-Column)
SELECT
DATE(d) AS day,
MIN(ABS(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR))))) AS offset,
MIN(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))) AS controlOffset1,
MIN(TIME_TO_SEC(TIMEDIFF(DATE_ADD(DATE(d), INTERVAL 19 HOUR),d))) AS controlOffset2,
CASE
WHEN MIN(ABS(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR))))) = MIN(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))) && MIN(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))) > 0 THEN
DATE_Add(DATE_ADD(DATE(d), INTERVAL 19 HOUR), INTERVAL
MIN(ABS(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))))
SECOND)
WHEN MIN(ABS(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR))))) = MIN(TIME_TO_SEC(TIMEDIFF(DATE_ADD(DATE(d), INTERVAL 19 HOUR),d))) THEN
DATE_SUB(DATE_ADD(DATE(d), INTERVAL 19 HOUR), INTERVAL
MIN(ABS(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))))
SECOND)
WHEN MIN(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))) = MIN(TIME_TO_SEC(TIMEDIFF(DATE_ADD(DATE(d), INTERVAL 19 HOUR),d))) THEN
DATE_ADD(DATE_ADD(DATE(d), INTERVAL 19 HOUR), INTERVAL
MIN(ABS(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))))
SECOND)
WHEN MIN(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))) <> MIN(TIME_TO_SEC(TIMEDIFF(DATE_ADD(DATE(d), INTERVAL 19 HOUR),d))) THEN
DATE_SUB(DATE_ADD(DATE(d), INTERVAL 19 HOUR), INTERVAL
MIN(ABS(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))))
SECOND)
END AS actualDate,
case
WHEN MIN(ABS(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR))))) = MIN(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))) && MIN(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))) > 0 THEN
"TEST#1"
WHEN MIN(ABS(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR))))) = MIN(TIME_TO_SEC(TIMEDIFF(DATE_ADD(DATE(d), INTERVAL 19 HOUR),d))) THEN
"TEST#2"
WHEN MIN(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))) = MIN(TIME_TO_SEC(TIMEDIFF(DATE_ADD(DATE(d), INTERVAL 19 HOUR),d))) THEN
"TEST#3"
WHEN MIN(TIME_TO_SEC(TIMEDIFF(d, DATE_ADD(DATE(d), INTERVAL 19 HOUR)))) <> MIN(TIME_TO_SEC(TIMEDIFF(DATE_ADD(DATE(d), INTERVAL 19 HOUR),d))) THEN
"TEST#4"
END AS testCase
FROM
test
GROUP BY DATE(d)
数据:
CREATE table test (d datetime);
# TEST 1: Solution later
INSERT INTO test (d) values ("2015-10-23 19:10:00"); #this
INSERT INTO test (d) values ("2015-10-23 19:20:00");
INSERT INTO test (d) values ("2015-10-23 19:30:00");
INSERT INTO test (d) values ("2015-10-23 19:40:00");
INSERT INTO test (d) values ("2015-10-23 19:50:00");
# TEST 2: Solution earlier
INSERT INTO test (d) values ("2015-10-24 18:10:00");
INSERT INTO test (d) values ("2015-10-24 18:20:00");
INSERT INTO test (d) values ("2015-10-24 18:30:00");
INSERT INTO test (d) values ("2015-10-24 18:40:00");
INSERT INTO test (d) values ("2015-10-24 18:50:00");#this
# TEST 3: Solution later, but earlier available
INSERT INTO test (d) values ("2015-10-25 18:30:00");
INSERT INTO test (d) values ("2015-10-25 18:40:00");
INSERT INTO test (d) values ("2015-10-25 18:50:00");
INSERT INTO test (d) values ("2015-10-25 19:05:00"); #this
INSERT INTO test (d) values ("2015-10-25 19:10:00");
INSERT INTO test (d) values ("2015-10-25 19:20:00");
INSERT INTO test (d) values ("2015-10-25 19:30:00");
# Test 4: Solution earlier, but later available
INSERT INTO test (d) values ("2015-10-26 18:30:00");
INSERT INTO test (d) values ("2015-10-26 18:40:00");
INSERT INTO test (d) values ("2015-10-26 18:50:00");
INSERT INTO test (d) values ("2015-10-26 18:55:00"); #this
INSERT INTO test (d) values ("2015-10-26 19:10:00");
INSERT INTO test (d) values ("2015-10-26 19:20:00");
INSERT INTO test (d) values ("2015-10-26 19:30:00");
INSERT INTO test (d) values ("2015-10-26 19:40:00");
结果:
day offset controlOffset1 controlOffset2 actualDate testCase
October, 23 2015 00:00:00 600 600 -3000 October, 23 2015 19:10:00 TEST#1
October, 24 2015 00:00:00 600 -3000 600 October, 24 2015 18:50:00 TEST#2
October, 25 2015 00:00:00 300 -1800 -1800 October, 25 2015 19:05:00 TEST#3
October, 26 2015 00:00:00 300 -1800 -2400 October, 26 2015 18:55:00 TEST#4
http://sqlfiddle.com/#!9/951b5/22
解释:
- 当我们确定了
Min(Abs())的偏移量后,我们需要弄清楚,是需要add这个偏移量到7pm的值,还是subtract它。
- 我们使用 2 个控制偏移来确定:
- 控制偏移1:
MIN(actualDate - 7pm)
- controlOffset2:
MIN(7pm - actualDate)
- 案例 1:offset 匹配 controlOffset1:我们的实际日期晚于目标 -> 使用
DATE_ADD
- 案例 2:offset 匹配 controlOffset2:我们的实际日期早于目标 -> 使用
DATE_SUB
- 案例 3:controlOffset1 匹配 controlOffset2:我们的实际日期晚于目标,但其他日期早于:使用
DATE_ADD
- 案例 4:甚至与案例 3 都不匹配:必须是案例 4,使用
DATE_SUB :-)
现在唯一undertermined 可能是,如果两个日期是 +/- 且具有相同的偏移量,即 +/- 5 分钟。因此,无论如何结果都是不确定的,因此您应该能够通过使用>= 或<= 扩展某些条件来获得非空值。 (编辑:将与案例3匹配,选择较晚的日期:http://sqlfiddle.com/#!9/21f2ce/2)
ps.:与应用程序端迭代方法中的“单次获取”相比,最终解决方案在性能方面的表现会很有趣。
*比较偏移量:为什么Min(d - 7pm) 与Min(7pm -d) 的偏移量不同 - 而不仅仅是符号?因为d 由于缺少聚合而未确定。因此,通过两个控制偏移量,我们可以根据7pm 确定值, 正确聚合并因此可靠。)