选择连续日期的最近时间

时间:2015-10-23 19:52:10

标签: c# mysql datetime

假设我有日期时间格式的日期列表:

6/30/2015 10:44:44 PM
6/30/2015 11:00:24 PM 
7/1/2015 12:22:46 AM    
7/1/2015 12:26:38 AM 
7/1/2015 2:55:04 AM 
7/1/2015 3:23:00 AM 
7/1/2015 3:32:09 AM 
7/1/2015 3:52:27 AM 
7/1/2015 3:57:25 AM 
7/1/2015 4:03:34 AM 
7/1/2015 4:23:52 AM 
7/1/2015 4:32:00 AM 
7/1/2015 4:50:03 AM    
7/1/2015 4:54:46 AM 
7/1/2015 5:10:20 AM 
7/1/2015 5:13:37 AM 
7/1/2015 5:18:51 AM 
.... 
7/31/2015 11:18:51 PM

我想抓住列表中每个日期的最近时间到5 AM。 我应该怎么做呢?

SELECT TOP 1 *
FROM x
WHERE x.date < @CurrentDate
ORDER BY x.date DESC

应该抓住最近的日期到当前日期,但每个不同的日期?

2 个答案:

答案 0 :(得分:3)

您可以使用TIMEDIFFTIME_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
  • 分组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 - 列)

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它。< / LI>
  • 我们使用2个控制偏移来确定:
    • controlOffset1:MIN(actualDate - 7pm)
    • controlOffset2:MIN(7pm - actualDate)
  • 案例1:偏移匹配controlOffset1 :我们的实际日期晚于目标 - &gt;使用DATE_ADD
  • 案例2:偏移匹配controlOffset2 :我们的实际日期比目标更早 - &gt;使用DATE_SUB
  • 案例3: controlOffset1匹配controlOffset2 :我们有一个实际日期晚于目标,但其他日期之前:使用DATE_ADD
  • 案例4:一切甚至不匹配案例3 :Musst是案例4,使用DATE_SUB: - )

如果两个日期是+/-且具有相同的偏移量,即+/- 5分钟,那么暗示的唯一内容现在可能是。因此,无论如何结果都是未确定的,因此您应该通过使用>=<=扩展某些条件来获取非空值。 (编辑:将与案例3匹配,选择较晚的日期:http://sqlfiddle.com/#!9/21f2ce/2

ps:与应用程序端迭代方法中的“单次提取”相比,最终解决方案在性能方面的表现会很有趣。

*比较偏移量:为什么Min(d - 7pm)的偏移量不同于Min(7pm -d) - 而且不仅仅是符号?因为缺少聚合而导致d未确定。因此,使用两个控制偏移量,我们可以根据7pm确定值, 正确聚合,因此可靠。)

答案 1 :(得分:0)

在平等时间凌晨5点之前和之后考虑:

select d, min(if(diff < 0, subtime(subtime(diff,diff),diff), diff)) diff from(
    select date(d) d, timediff(time(d), maketime(5,0,0)) diff from dt
) q
group by d;