0

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

表单通常每天提交,但用户可以决定每天提交多个。

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

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

回顾:

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

澄清

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

3 回答 3

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'
于 2013-08-19T17:11:10.287 回答
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()应该替换为您将在流程开始时计算的文字值(否则您将不会WHERE随着时间的推移在相同的条件下进行过滤)

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

于 2013-08-19T17:33:34.780 回答
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 子句中的计数。如果计数小于 40,那么我们不包含任何其他谓词(获取所有行)。

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

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

(具有前导列的索引submitted_timestamp可能会提高性能。

于 2013-08-19T19:00:21.213 回答