Mysql SELECT 在时间限制内只返回列匹配的最近和下一个最近的行

标签 mysql date

更新:下面 Kordirko 的解决方案在 SQL Fiddle 中确实有效,但正如我在评论中提到的,该代码在我自己的 mysql 数据库中不起作用。我直接复制了架构命令并从 fiddle 运行查询的副本。我检查了两者,它们是相同的代码。我在我的数据库和 fiddle 之间验证了相同的 5.1.61 mysql 版本。在实时数据库中,id 2 返回 3 行,而在 fiddle 上仅返回 2 行(预期效果)。 fiddle 可以在传递查询之前更改查询吗?

背景:

我有一个数据表,保存为扫描结果的历史记录。通常它用于绘制结果随时间变化的趋势,但我想尝试其他方法。如果至少有 2 个数据点,我想提供最近的向上或向下趋势(以百分比表示)。更具体地说,我还想将其限制为最近 7 天,以将趋势范围限制在事件项目中。

请注意,该表仅在项目第一次运行时以及 issues_count 与上一次运行相比发生变化时更新。

示例表:

id  issues_count  updated
1   7922          2013-10-02 08:22:31
1   7981          2013-10-03 08:22:43
2   7754          2013-10-10 12:06:45
2   7922          2013-10-11 12:06:45
2   7981          2013-10-12 02:09:43
3   15536         2013-10-12 02:09:43
4   1233          2013-10-11 12:06:45
4   2493          2013-10-12 02:09:43
5   4349          2013-10-12 02:09:44

表结构:

CREATE TABLE IF NOT EXISTS `issue_history` (
  `id` bigint(20) unsigned NOT NULL,
  `issues_count` mediumint(8) unsigned NOT NULL,
  `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  KEY `id_index` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=ascii;

结果逻辑:

在上面的示例中,我想忽略两个“1”id 条目,因为它们早于 7 天(从今天开始)。我不想为 id '3' 和 id '5' 返回任何内容,因为到目前为止它们只有一个数据点。对于 ID“2”和“4”,我想根据时间戳返回最近的和直接在它之前的那个(不在此之前,最多 2 个)。

示例结果:

2   7922          2013-10-11 12:06:45
2   7981          2013-10-12 02:09:43
4   1233          2013-10-11 12:06:45
4   2493          2013-10-12 02:09:43

其他想法:

顺序并不是那么重要,尽管我可能希望首先按 id(asc 或 desc)对它们进行分组,然后按 desc 中的时间戳进行分组。

如果我要进行低效的尝试,我可以通过对过去 24 小时内的所有 ID 进行选择来处理这个问题,然后可能选择与这些 ID 匹配的所有行,按时间戳 desc 排序,限制为 2。然后我的代码必须删除每个 ID 少于 2 行的结果。可能我会继续从第一个中选择一个子查询并嵌入到第二个中。我仍然认为这不是最好的方法,但应该有效。

我担心的是该表可能会以每天几千行的速度增长,我想尽可能花最少的时间来运行命令。我特别不想从程序中两次访问数据库。

最佳答案

试试这个查询:

SELECT id,
       issues_count,
       updated
FROM (
  SELECT sub1.*,
         IF(@last_id=sub1.id,(@rn:=@rn+1),(@rn:=1)) rn,
         (@last_id:=sub1.id) last_id
  FROM (
     SELECT ih.* 
     FROM issue_history ih
     JOIN (
       SELECT id
       FROM issue_history
        -- the most recent 7 days 
        WHERE updated > now() - interval 7 day
        GROUP BY id
        -- if there are at least 2 data points
        HAVING count(*) >= 2
     ) ih1
     ON ih.id = ih1.id AND ih.updated > now() - interval 7 day
     CROSS JOIN ( SELECT (@rn:=0),(@last_id=-12345)) init_variables
  ) sub1
  --  by id (asc or desc) and then by the timestamp in desc
  ORDER BY sub1.id ASC, sub1.updated DESC
) subquery
-- not any prior to that, 2 max
WHERE rn <= 2
ORDER BY id ASC, updated ASC

演示 ---> http://www.sqlfiddle.com/#!2/4309b/30


------ 编辑 --------------

确定配对的最近日期并按此日期对记录进行排序的另一个版本

SELECT id,
       issues_count,
       updated,
       most_recent_date
FROM (
  SELECT sub1.*,
         IF(@last_id=sub1.id,(@rn:=@rn+1),(@rn:=1)) rn,
         (@last_id:=sub1.id) last_id
  FROM (
     SELECT ih.*, ih1.most_recent_date
     FROM issue_history ih
     JOIN (
       -- max( updated ) --> most recent date
       SELECT id, max( updated ) most_recent_date
       FROM issue_history
        -- the most recent 7 days 
        WHERE updated > now() - interval 7 day
        GROUP BY id
        -- if there are at least 2 data points
        HAVING count(*) >= 2
     ) ih1
     ON ih.id = ih1.id AND ih.updated > now() - interval 7 day
     CROSS JOIN ( SELECT (@rn:=0),(@last_id=-12345)) init_variables
  ) sub1
  --  by id (asc or desc) and then by the timestamp in desc
  ORDER BY sub1.id ASC, sub1.updated DESC
) subquery
WHERE rn <= 2
ORDER BY most_recent_date, id, updated

演示 --> http://www.sqlfiddle.com/#!2/1eb9fe/1

关于Mysql SELECT 在时间限制内只返回列匹配的最近和下一个最近的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19339215/

相关文章:

Mysql - 将两行与值对合并

Php - 从 gmdate() 日期中减去天数

java - Hibernate Search 中 LocalDate 的 DateBridge

r - 转换为日期格式错误: character string is not in a standard unambiguous format

mysql - 缓慢删除临时表

php - Firebase 使用 php 过滤数据

python - 在cursor.execute(query) mysql.connector Python中使用multi=True

mysql - 求职网站数据库设计

ios - 如何在不丢失格式的情况下将字符串转换为日期

mysql - Spring Boot - Hibernate 未正确保存日期