SQL将样本点转换为持续时间

时间:2012-09-14 19:35:49

标签: sql algorithm

这与Compute dates and durations in mysql query类似,不同之处在于我没有可以使用的唯一ID列,并且我的样本不是开始/结束点。

作为一个有趣的实验,我将cron设置为ps aux > 'date +%Y-%m-%d_%H-%M'.txt。我现在有大约250,000个“机器正在运行的”样本。

我想把它变成“process | cmd | start | stop”的列表。假设“开始”事件是该对存在的第一次,并且“停止”事件是它停止存在的第一个样本:没有样本“遗漏”或任何东西的可能性。

那说,进行这种转换的方式有多少,最好是使用SQL(基于我喜欢SQL,这似乎是一个很好的挑战)。假设pids不能重复,这是一项微不足道的任务(将所有内容放在表格SELECT MIN(time), MAX(time), pid GROUP BY pid中)。但是,由于PID / cmd对重复(我检查过,有重复),我需要一个方法来执行真正的“查找所有连续段”搜索。

如果有必要,我可以采用

形式
Load file0 -> oldList
ForEach fileN:
    Load fileN ->newList
    oldList-newList = closedN
    newList-oldList = openedN
    oldList=newList

但这不是SQL,也不是很有趣。谁知道,我可能最终会得到真正的SQL数据来处理这个属性。

我正在考虑的事情是,首先构建一个差异表,然后将所有关闭对象连接到所有开放状态,并在每次打开后拉近最小距离,但我想知道是否有更好的方法。

1 个答案:

答案 0 :(得分:1)

您没有提到您正在使用的数据库。我假设您正在使用支持排名功能的数据库,因为这简化了解决方案。

解决这个问题的关键是观察。您希望为每个pid分配一个ID,以查看它是否唯一。我将假设当pid在上一个带时间戳的输出中出现 not 时,pid代表一个进程。

现在,想法是:

  1. 为每组输出分配一个序号。对ps的第一次调用得到1,接下来是2,依此类推,基于日期。
  2. 根据日期为每个pid分配一个序号。第一个外观为1,下一个为2,依此类推。
  3. 对于按顺序出现的pid,差异是常数。我们可以将其称为该集合的groupid。
  4. 所以,这是行动中的查询:

    select groupid, pid, min(time), max(time)
    from (select t.*,
                 (dense_rank() over (order by time) -
                  row_number() over (partition by pid order by time)
                 ) as groupid
          from t
         ) t
    group by groupid, pid
    

    这适用于大多数数据库(SQL Server,Oracle,DB2,Postgres,Teradata等)。它在MySQL中不起作用,因为MySQL不支持窗口/分析函数。