主要通过时间限制MySQL行,然后(可能)按行数限制

时间:2013-08-19 17:06:42

标签: mysql

我有一个MySQL表,用于存储来自用户数据的输入,并为每个提交的表单添加时间戳。

表格通常每天提交,但用户可以决定每天进​​行多次。

我必须显示一个显示过去6周数据的图表,或者,如果6周的数据不包含足够的数据点(40)我必须限制点数(它可以从早期获得数据点)日期)。

我可以在一个查询中执行此操作,还是应该依赖一些更复杂的SQL,或者更糟糕的是我必须依赖我的Python / PHP / C ++ / ... wathever?

回顾:

  • 最少6周的数据
  • 如果在所选范围内没有40个数据点 - >无论时间戳限制如何,都要拿走最后40个。

澄清

  • 如果时间范围内的元素数量是60,我想要这60个元素。
  • 如果时间范围内的元素数是30,我想要最后40个元素。

3 个答案:

答案 0 :(得分:1)

select t2.* from  (
 SELECT t.*, 
   @rownum := @rownum + 1 AS rownumber
 FROM YOUR_TABLE t, 
   (SELECT @rownum := 0) r
 ORDER BY timestamp
) as t2
where t2.rownumber<=40 or t2.timestamp >= '6-week-date'

答案 1 :(得分:1)

当然,有很多方法可以在一个查询中实现这一点,但我怀疑它是否可以高效地完成。假设您的表在日期/时间字段上编入索引,这样的查询应该是即时的:

SELECT COUNT(dateField) FROM myTable
WHERE dateField >= DATE_SUB(NOW(), INTERVAL 6 WEEK);

然后我将进行两次传递,并根据上述查询的返回值触发这两个版本中的任何一个:

-- if previous query returned < 40
SELECT * FROM myTable
ORDER BY dateField DESC
LIMIT 40;

-- if previous query returned >= 40
SELECT * FROM myTable
WHERE dateField >= DATE_SUB(NOW(), INTERVAL 6 WEEK);

通知:

  • NOW()应该替换为您在流程开始时计算的一个litteral值(否则您将不会在时间过去时在相同的WHERE条件下进行过滤)

  • 第一个SELECT语句实际上应该是一个锁定SELECT ... FOR UPDATE语句,以便在获得真实数据(第二个查询)之前防止干扰。当然,这将在一次交易中发生。

答案 2 :(得分:0)

我会这样做:

SELECT t.*
  FROM mytable t
 CROSS 
  JOIN ( SELECT COUNT(1) AS cnt
           FROM mytable ct
          WHERE c.submitted_timestamp >= NOW() + INTERVAL -6 WEEK
       ) c
 WHERE ( c.cnt <= 40 )
    OR ( c.cnt > 40 AND t.submitted_timestamp >= NOW() + INTERVAL -6 WEEK )
 ORDER
    BY t.submitted_timestamp DESC
 LIMIT 40 

内联视图(上面指定了c的别名)返回指定时间段(6周)内带时间戳的数量。

我们在外部查询的WHERE子句中使用为count返回的值。如果计数小于40,那么我们不包括任何其他谓词(获取所有行)。

如果计数大于40,那么我们包含一个额外的谓词。

ORDER BY向我们保证我们首先拥有最新的行。 LIMIT确保我们返回不超过40行。

(前导列为submitted_timestamp的索引可能会提高效果。