【问题标题】:Time interval SQL query with MySQL使用 MySQL 的时间间隔 SQL 查询
【发布时间】:2012-05-25 10:06:02
【问题描述】:

我在数据库中有一个按时间存储日志数据的表。一天之内,数据库中可能有一百万行。时间没有任何固定的间隔。它有几个索引,包括时间。我想要做的是构建一个查询,该查询将返回一组行,每个时间间隔一行。例如,我可以执行查询以在一天内每 15 分钟返回 1 行。这将返回 24*60=96 行。返回的每一行实际上是请求间隔之前数据库中最近的行(因为数据库中的数据不等于请求的间隔)。

我不知道该怎么做。我不能只为一组特定的索引和时间间隔查询所有行,因为它会将超过 1 GB 的数据加载到内存中,这太慢了。有没有任何有效的方法可以使用 SQL 来做到这一点。我正在使用 MySQL 数据库。我愿意更改表索引/等...

TIME

11:58
12:03
12:07
12:09
12:22
12:27
12:33
12:38
12:43
12:49
12:55

如果我想查询这个从 12:00 到 1:00 的 15 分钟间隔,我会回复:

11:58 (nearest 12:00)
12:09 (nearest 12:15)
12:27 (nearest 12:30)
12:43 (nearest 12:45)
12:55 (nearest 1:00) 

如果它更容易,我还可以将时间存储为数字(即自 1970 年以来的毫秒)。在上述查询中,这将是 900000 毫秒的间隔。

【问题讨论】:

  • 如果在给定的时间间隔内有多于一行,应该使用哪一行?还是应该是行的某种组合?
  • 是否需要每个区间出现?如果没有记录怎么办?如果一个记录最接近两个不同的时间间隔(即 11:58、12:27、01:14 将 12:14 最接近 12:15、12:30 和 12:45
  • 如果该区间内没有记录,则该区间内没有记录是可以的。

标签: mysql sql group-by


【解决方案1】:

所以,我想到了类似的东西:

SELECT 
  MIN(timeValue)
FROM e
GROUP BY (to_seconds(timeValue) - (to_seconds(timeValue) % (60 * 5)))

..会为你做,但这只会返回整个表的 MIN(timeValue)。如果四舍五入到最接近的 5 分钟的秒数在其自己的列中,则它可以工作。

SQL Fiddle

根据 Andiry 进行编辑,这可行:(http://sqlfiddle.com/#!2/bb870/6)

SELECT MIN(t)
FROM e
GROUP BY to_seconds(t) DIV (60 * 5)

但这只是给出一行:(http://sqlfiddle.com/#!2/bb870/7

SELECT MIN(t)
FROM e
GROUP BY to_seconds(t) - (to_seconds(t) % (60 * 5))

有人知道为什么吗?

【讨论】:

  • to_seconds(timeValue) DIV (60 * 5) 将等效且更简洁。你为什么说这只会返回整个表的最小值?您在此处对行进行分组,因此每组将返回 MIN()。 (虽然我认为 MAX() 而不是 MIN() 会更接近 OP 所追求的。)
  • 感谢 DIV 提示,以及您对 MAX() 的正确看法 - 我只是想接近目标。
  • @deathApril nope - 它在我的服务器上的行为相同 o.O 如果我使用 UNIX_TIMESTAMP(t) 它会按预期工作......
  • @Andrew 这看起来很有希望,我明天在我们的数据库上试一试。
  • 我没有费心测试您的建议,因此无法理解它的问题。现在我已经测试过了,我明白你的意思了。这对我来说似乎是一个错误。我可以通过计算表达式来解决这个问题(see here)。但我认为它应该像你建议的那样工作,没有额外的转换和子选择大惊小怪,这就是我认为这是一个错误的原因。
【解决方案2】:

我想不出一种在一个查询中完成所有操作的好方法。也许其他人可以想到更好的方法,但也许您可以使用这样的方法:

$startTime = mktime(12, 0);
$endTime = mktime(13, 0);
$queries = array();
for ($i = $startTime; $i <= $endTime; $i += 900)
    $queries[] = "SELECT MAX(timeValue) FROM table1 WHERE timeValue < '". date("G:i", $i) ."'";

$query = implode("\nUNION\n", $queries);

我刚刚意识到这是假设您使用的是 PHP。如果不是,则只需使用生成的查询,如下所示:

SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:00'
UNION
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:15'
UNION
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:30'
UNION
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:45'
UNION
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '13:00'

不确定&lt; 比较是否能 100% 正确处理这些字符串值,但我绝对认为将它们切换为 unix 时间戳(或自 1970 年以来的毫秒,如果你需要这么多粒度的话)是个好主意.我发现使用日期/时间的整数值而不是字符串总是更容易。

【讨论】:

  • 谢谢。我会试一试。我认为的问题是,我需要以 1 分钟到 15 分钟的间隔执行一整天,这相当于 96 到 1440 个查询,这可能很慢。
【解决方案3】:

我认为使用函数非常简单,我没有注意到很大的性能影响,尽管游标可能会更好地执行,具体取决于两次之间的行数。

CREATE TABLE TEST_TIMES (EventTime datetime)
-- skipping INSERTS of your times

CREATE FUNCTION fn_MyTimes ( @StartTime datetime, @EndTime datetime, @Minutes int )
    RETURNS @TimeTable TABLE (TimeValue datetime)
AS BEGIN
    DECLARE @CurrentTime datetime
    SET @CurrentTime = @StartTime
    WHILE @CurrentTime <= @EndTime
    BEGIN
        INSERT INTO @TimeTable VALUES (@CurrentTime)
        SET @CurrentTime = DATEADD(minute, @Minutes, @CurrentTime)
    END
    RETURN
END

CREATE FUNCTION fn_ClosestTime ( @CheckTime datetime )
    RETURNS datetime
AS BEGIN
    DECLARE @LowerTime datetime, @HigherTime datetime

    SELECT @LowerTime = MAX(EventTime)
    FROM TEST_TIMES
    WHERE EventTime <= @CheckTime

    SELECT @HigherTime = MAX(EventTime)
    FROM TEST_TIMES
    WHERE EventTime >= @CheckTime

    IF @LowerTime IS NULL RETURN @HigherTime -- both null?  then null
    IF @HigherTime IS NULL RETURN @LowerTime

    IF DATEDIFF(ms, @LowerTime, @CheckTime) < DATEDIFF(ms, @CheckTime, @HigherTime)
        RETURN @LowerTime
    RETURN @HigherTime
END

SELECT TimeValue, dbo.fn_ClosestTime(TimeValue) as ClosestTime
FROM fn_MyTimes('2012-05-17 12:00', '2012-05-17 13:00', 15)

结果:

TimeValue               ClosestTime
----------------------- -----------------------
2012-05-17 12:00:00.000 2012-05-17 11:58:00.000
2012-05-17 12:15:00.000 2012-05-17 12:09:00.000
2012-05-17 12:30:00.000 2012-05-17 12:27:00.000
2012-05-17 12:45:00.000 2012-05-17 12:43:00.000
2012-05-17 13:00:00.000 2012-05-17 12:55:00.000

【讨论】:

  • 我看到 MYSQL 不允许函数返回表,我搜索的第一个链接显示了它,但它是 was a plugin
猜你喜欢
  • 2023-02-21
  • 2020-02-14
  • 1970-01-01
  • 2021-03-02
  • 1970-01-01
  • 2021-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多