MySQL GROUP BY DateTime +/- 3秒

Bra*_*rad 15 mysql sql group-by datetime-generation

假设我有一个包含3列的表:

  • id(PK,int)
  • 时间戳(日期时间)
  • 标题(文字)

我有以下记录:

1, 2010-01-01 15:00:00, Some Title
2, 2010-01-01 15:00:02, Some Title
3, 2010-01-02 15:00:00, Some Title
Run Code Online (Sandbox Code Playgroud)

我需要做一个彼此在3秒内的GROUP BY记录.对于此表,第1行和第2行将组合在一起.

这里有一个类似的问题: Mysql DateTime组15分钟

我也发现了这个:http: //www.artfulsoftware.com/infotree/queries.php#106

我不知道如何将这些方法转换为可以工作几秒钟的方法.在SO问题上方法的问题在于,在我看来它只适用于落在从已知点开始的时间仓内的记录.例如,如果我FLOOR()以秒为单位工作,间隔为5秒,则15:00:04的时间将与15:00:01分组,但不会与15:00:06分组.

这有意义吗?如果需要进一步说明,请与我们联系.

编辑:对于一组数字,{1,2,3,4,5,6,7,50,51,60},似乎最好将它们分组{1,2,3,4,5, 6,7},{50,51},{60},以便每个分组行取决于行是否在前一个3秒内.我知道这会改变一些事情,对不起,我很抱歉.

我试图模糊匹配来自不同服务器的日志.服务器#1可以记录项目"项目#1",服务器#2将在服务器#1的几秒内记录相同的项目"项目#1".我需要在两个日志行上做一些聚合函数.不幸的是,由于服务器软件的性质,我只有标题可以继续.

Chr*_*ham 15

我正在使用Tom H.的优秀想法,但在这里做的有点不同:

我们可以找到作为链的起点的所有时间,而不是找到作为链的开头的所有行,然后返回并且ifnd匹配时间的行.

这里的查询#1应该告诉您哪些时间是链的开头,通过查找哪些时间在它们之下没有任何时间但在3秒内:

SELECT DISTINCT Timestamp
FROM Table a
LEFT JOIN Table b
ON (b.Timestamp >= a.TimeStamp - INTERVAL 3 SECONDS
    AND b.Timestamp < a.Timestamp)
WHERE b.Timestamp IS NULL
Run Code Online (Sandbox Code Playgroud)

然后对于每一行,我们可以找到最小的链起始时间戳,该时间戳小于查询#2的时间戳:

SELECT Table.id, MAX(StartOfChains.TimeStamp) AS ChainStartTime
FROM Table
JOIN ([query #1]) StartofChains
ON Table.Timestamp >= StartOfChains.TimeStamp
GROUP BY Table.id
Run Code Online (Sandbox Code Playgroud)

一旦我们拥有了它,我们可以根据需要GROUP BY它.

SELECT COUNT(*) --or whatever
FROM Table
JOIN ([query #2]) GroupingQuery
ON Table.id = GroupingQuery.id
GROUP BY GroupingQuery.ChainStartTime
Run Code Online (Sandbox Code Playgroud)

我不完全确定这与Tom H的答案分开是否足够明显,但听起来好像你在实施方面遇到了麻烦,而我正在思考它,所以我想我会再次发帖.祝好运!


Tom*_*m H 5

现在我认为我理解你的问题,基于你对OMG Ponies的评论回应,我认为我有一个基于集合的解决方案.我们的想法是首先根据标题找到任何链的起点.链的开头将被定义为在该行之前三秒内没有匹配的任何行:

SELECT
    MT1.my_id,
    MT1.title,
    MT1.my_time
FROM
    My_Table MT1
LEFT OUTER JOIN My_Table MT2 ON
    MT2.title = MT1.title AND
    (
        MT2.my_time < MT1.my_time OR
        (MT2.my_time = MT1.my_time AND MT2.my_id < MT1.my_id)
    ) AND
    MT2.my_time >= MT1.my_time - INTERVAL 3 SECONDS
WHERE
    MT2.my_id IS NULL
Run Code Online (Sandbox Code Playgroud)

现在我们可以假设任何非链起动器都属于它们之前出现的链起动器.由于MySQL不支持CTE,您可能希望将上述结果抛出到临时表中,因为这样可以节省下面相同子查询的多个连接.

SELECT
    SQ1.my_id,
    COUNT(*)  -- You didn't say what you were trying to calculate, just that you needed to group them
FROM
(
    SELECT
        MT1.my_id,
        MT1.title,
        MT1.my_time
    FROM
        My_Table MT1
    LEFT OUTER JOIN My_Table MT2 ON
        MT2.title = MT1.title AND
        (
            MT2.my_time < MT1.my_time OR
            (MT2.my_time = MT1.my_time AND MT2.my_id < MT1.my_id)
        ) AND
        MT2.my_time >= MT1.my_time - INTERVAL 3 SECONDS
    WHERE
        MT2.my_id IS NULL
) SQ1
INNER JOIN My_Table MT3 ON
    MT3.title = SQ1.title AND
    MT3.my_time >= SQ1.my_time
LEFT OUTER JOIN
(
    SELECT
        MT1.my_id,
        MT1.title,
        MT1.my_time
    FROM
        My_Table MT1
    LEFT OUTER JOIN My_Table MT2 ON
        MT2.title = MT1.title AND
        (
            MT2.my_time < MT1.my_time OR
            (MT2.my_time = MT1.my_time AND MT2.my_id < MT1.my_id)
        ) AND
        MT2.my_time >= MT1.my_time - INTERVAL 3 SECONDS
    WHERE
        MT2.my_id IS NULL
) SQ2 ON
    SQ2.title = SQ1.title AND
    SQ2.my_time > SQ1.my_time AND
    SQ2.my_time <= MT3.my_time
WHERE
    SQ2.my_id IS NULL
Run Code Online (Sandbox Code Playgroud)

如果您可以使用CTE或使用临时表,这看起来会简单得多.使用临时表也可能有助于提高性能.

此外,如果您可以准确匹配时间戳,则会出现此问题.如果是这种情况,那么您需要稍微调整查询以使用id和时间戳的组合来区分具有匹配时间戳值的行.

编辑:更改查询以按时间戳处理完全匹配.