MySQL选择时间戳最接近但不超过给定时间戳的行

时间:2015-05-15 13:39:45

标签: mysql sql

我有一张表格如下所示

state_history
+---------------------+-----------+----------------+      +
| state_added_time    | entity_id | state_id       | .... |
+---------------------+-----------+----------------+      |
| 2015-05-15 13:24:22 |         1 |              1 |      |
| 2015-05-15 13:29:44 |         3 |              2 |      |
| 2015-05-15 13:34:26 |         2 |              2 |      |
| 2015-05-15 14:24:28 |         1 |              3 |      |
| 2015-05-15 14:24:30 |         2 |              3 |      |
| 2015-05-15 14:26:32 |         3 |              5 |      |
| 2015-05-15 14:26:34 |         3 |              3 |      |
.......

我的目的是在任何特定时间了解所有实体的状态。例如,如果从应用程序收到的时间戳为2015-05-15 14:25:00,则预期输出应为:

state_history
+---------------------+-----------+----------------+      +
| state_added_time    | entity_id | state_id       | .... |
+---------------------+-----------+----------------+      |
| 2015-05-15 14:24:28 |         1 |              3 |      |
| 2015-05-15 14:24:30 |         2 |              3 |      |
| 2015-05-15 13:29:44 |         3 |              2 |      |
.......

即,知道在给定时间之前或之后每个实体发生的最后状态变化。状态变化之间的间隔不固定。因此,我不能有2个时间边界,并在它们之间找到行。

我尝试使用TIMEDIFF但未能获得所需的输出。有人可以指导我走的路吗?

编辑:感谢大家的快速回复。我尝试了答案,并注意到在实际数据库上执行时,查询需要花费大量时间来获取行。可能是因为字段entity_idstate_id是其他两个表的外键。 既然已知这有什么方法可以提高查询的性能吗?

7 个答案:

答案 0 :(得分:3)

你在找这个吗?

SELECT h.*
  FROM 
(
  SELECT entity_id, MAX(state_added_time) state_added_time
    FROM state_history
   WHERE state_added_time <= '2015-05-15 14:25:00'
  GROUP BY entity_id
) q JOIN state_history h
    ON q.entity_id = h.entity_id
   AND q.state_added_time = h.state_added_time

输出:

|      state_added_time | entity_id | state_id |
|-----------------------|-----------|----------|
| May, 15 2015 13:29:44 |         3 |        2 |
| May, 15 2015 14:24:28 |         1 |        3 |
| May, 15 2015 14:24:30 |         2 |        3 |

这是 SQLFiddle 演示

答案 1 :(得分:3)

为此,您可以使用一些简单的聚合。您只需要// Before all your routes routeBuilder.MapRoute( "Root", "", defaults: new { controller = "Home", action = "Index" }); // Your routes here // After all your routes routeBuilder.MapRoute( "DeepLink", "{*pathInfo}", defaults: new { controller = "Home", action = "Index" }); 函数来获取每个entity_id的最大时间,条件是它小于给定的时间戳。

一旦你有了每个entity_id的时间,你需要将它连接回原始表,以便获得state_id值。它看起来像这样:

MAX()

以下是SQL Fiddle示例。

答案 2 :(得分:3)

您也可以使用变量:

SELECT entity_id, state_added_time, state_id
FROM (
  SELECT state_added_time, state_id,
          @row_number:= CASE WHEN @entity = entity_id THEN @row_number+1
                             ELSE 1
                        END AS row_number,
          @entity:=entity_id AS entity_id   
  FROM state_history
  WHERE state_added_time <= '2015-05-15 14:25:00'
ORDER BY entity_id, state_added_time DESC ) t
WHERE t.row_number = 1
每次遇到新的@row_number时,

entity_id都会被重置。在每个entity_id中,@row_number = 1的值指向最近的记录。

SQL Fiddle Demo

答案 3 :(得分:1)

从集合的角度考虑这一点。您需要一组包含最大日期的数据,该日期小于或等于按实体分组提供的日期。可以将这组数据生成为内联视图。 (我打电话给B)一旦你有了这个集合,就把它连接回基础集,把它连接回基集来获得额外的字段。

SaveChangesAsync

答案 4 :(得分:0)

尝试

SELECT * FROM state_history WHERE UNIX_TIMESTAMP(state_added_time) <= UNIX_TIMESTAMP('2015-05-15 14:25:00')

答案 5 :(得分:0)

不确定你是否可以做到

SELECT * From state_history where state_added_time  <= '2015-05-15 14:25:00' ORDER BY  state_added_time DESC

答案 6 :(得分:0)

SELECT s.*
from (select Max(state_added_time) AS maxts, entity_id 
      FROM   state_history
      WHERE state_added_time <= "2015-05-15 14:25:00" 
      GROUP  BY entity_id
) as m inner join state_history s 
on s.state_added_time = m.maxts
and s.entity_id = m.entity_id

sqlfiddle:http://sqlfiddle.com/#!9/884ee/12/0