MySQL:按计算的步长间隔限制结果

时间:2011-06-07 17:44:15

标签: mysql sql database

我需要在给定的开始和停止时间内以动态计算的步长间隔从查询中返回特定数量的行。

我在这里保持简单,其中包含一个由unix时间戳和相应的整数值组成的表。

在我的示例中,我需要返回 200 行,INCLUSIVE开始时间为 1307455099 ,并且INCLUSIVE结束时间 1307462455

这是我目前开发的当前查询。它使用总行数来计算步长间隔:

SELECT timestamp, value FROM soh_data
WHERE timestamp % (CAST((1307462455 - 1307455099)/200 AS SIGNED INTEGER)) = 0
AND timestamp BETWEEN 1307455099 AND 1307462455 
ORDER BY timestamp;

第一个问题是,因为我使用的是模数,所以开始和结束时间并不总是包含在内的(这可以通过额外的查询来解决......我很好)。

第二个也是更难解决的问题是,在这种情况下返回的总行数仅为196.在大多数查询中,它是n-1。

仅供参考,这是一个拥有数百万行数据的MySQL数据库。

任何见解?

2 个答案:

答案 0 :(得分:2)

由于丢弃了几行我很好,但是由于数据太少我不行,我提出了两种不同的方法。

首先:我决定调整我的查询以使用FLOOR而不是CAST。在我的例子中,除法的商是21.805。 SQL四舍五入到22个。收集200多个结果的正确步骤间隔是21(产生205个结果)。使用FLOOR将给出我需要的步数21。不幸的是,我没有对此进行全面测试,以确保在较大的集合中获得一致的结果:

SELECT DISTINCT timestamp FROM soh_data 
WHERE timestamp % (FLOOR((1307459460 - 1307455099)/200)) = 0 
AND timestamp BETWEEN 1307455099 AND 1307459460 
ORDER BY timestamp;

更可靠的解决方案是预先计算代码中的步骤。这样,我可以通过编程方式将步骤归零。在下面的例子中,我使用Ruby来提高可读性,但我的最终解决方案将用C ++编写:

lower = 1307455099
upper = 1307459460

limit = 200
range = lower..upper
matches = 0
stepFactor = ((upper-1) - (lower+1))/limit

while (matches <= (limit - 2)) do
    matches = 0

    range.each { |ts| matches += 1 if (ts % stepFactor == 0) }

    stepFactor -= 1 # For the next attempt

    puts "Step factor = #{stepFactor+1}"
    puts "Matches = #{matches}"
end

答案 1 :(得分:0)

当然,返回的行数完全取决于与条件匹配的时间戳数量。假设您的步长值为2,因此您的模数学可归结为“仅偶数编号的时间戳”。如果表中的所有项目都有奇怪的时间戳,那么即使在时间范围内有500多个项目,也会返回0行。

如果您只需要200,那么以某种方式使用LIMIT可能会更好。