【问题标题】:Updating status timespan and removing unneeded rows with SQL使用 SQL 更新状态时间跨度并删除不需要的行
【发布时间】:2013-06-04 15:07:54
【问题描述】:

假设我有一些服务器,它们不断更新数据库的状态。

我需要针对这些服务器的状态生成一些报告。对桌子做一点清理工作会很有帮助。

每条状态消息(开始时间和结束时间)都有 2 个时间戳。我想做的是采取具有相同状态的后续更新,并将其删除。我想更新结束时间以反映正确的时间间隔。

让我举例说明...

server_status 表:

server   |    status    |     start_time      |       end_time
---------+------------+---------------------+---------------------
 web1    |  running     | 2013-06-04 00:00:00 | 2013-06-04 00:05:00
 web2    |  down        | 2013-06-04 00:01:00 | 2013-06-04 00:03:00
 web1    |  running     | 2013-06-04 00:05:00 | 2013-06-04 01:00:00
 msdb    |  idle        | 2013-06-04 00:02:00 | 2013-06-04 02:00:00
 web1    |  running     | 2013-06-04 01:00:00 | 2013-06-04 02:00:00
 web2    |  down        | 2013-06-04 00:03:00 | 2013-06-04 03:00:00
 web2    |  running     | 2013-06-04 03:00:00 | 2013-06-04 05:00:00
 web1    |  maintenance | 2013-06-04 02:00:00 | 2013-06-04 05:00:00
 web1    |  running     | 2013-06-04 05:00:00 | 2013-06-04 07:00:00

我希望我的桌子最终看起来像这样(按 start_time 排序):

server   |    status    |     start_time      |       end_time
---------+------------+---------------------+---------------------
 web1    |  running     | 2013-06-04 00:00:00 | 2013-06-04 02:00:00
 web2    |  down        | 2013-06-04 00:01:00 | 2013-06-04 03:00:00
 msdb    |  idle        | 2013-06-04 00:02:00 | 2013-06-04 02:00:00
 web1    |  maintenance | 2013-06-04 02:00:00 | 2013-06-04 05:00:00
 web2    |  running     | 2013-06-04 03:00:00 | 2013-06-04 05:00:00
 web1    |  running     | 2013-06-04 05:00:00 | 2013-06-05 07:00:00

这让我知道我的盒子何时改变状态,然后当我对这些表运行一些报告时,我可以在 SQL 中查询 start_time 和 end_time。

任何线索如何做到这一点?我假设我需要一个更新语句,然后是一个删除。如果需要,我可以添加行号,尽管它们目前不存在。这可能是必要的,所以我们可以排序,然后检查 X 行的服务器和状态是否与 X + 1 行相同。

运行 postgres 8.1(我知道,我知道。很快就会到 8.4)。

【问题讨论】:

  • 检查我添加的样本数据行,确保输入和输出都正确。样本数据需要一个不连续的后行,该行与前一行具有相同的状态。
  • 是的。看起来不错。我一定错过了什么。

标签: sql postgresql timestamp delete-row timespan


【解决方案1】:

这是一个棘手的问题,因为同一个(server, status) 有多组值,所以简单的GROUP BYDISTINCT (ON) 不会解决问题。

但是,window function lag()(自 PostgreSQL 8.4 起可用)非常适合您的问题,使解决方案异常简单。

要在SELECT 中获取您要查找的值:

SELECT server, status, start_time, end_time
FROM  (
   SELECT *, status IS DISTINCT FROM 
             lag(status) OVER (PARTITION BY server ORDER BY start_time) AS step
   FROM   server_status
   ) sub
WHERE  step
ORDER  BY start_time;

旧版:这也应该适用于 8.1。仅使用 8.4 进行测试。
相关子查询可能比窗口函数慢很多。

SELECT server, status, start_time, end_time
FROM   server_status s
WHERE ( 
   SELECT s1.status
   FROM   server_status s1
   WHERE  s1.server = s.server
   AND    s1.start_time < s.start_time
   ORDER  BY s1.start_time DESC
   LIMIT  1
   ) IS DISTINCT FROM s.status
ORDER  BY start_time;

->SQLfiddle for both
根据需要发送至DELETE 行:

DELETE FROM server_status s
USING (
   SELECT server, status, start_time
         ,status IS DISTINCT FROM
          lag(status) OVER (PARTITION BY server ORDER BY start_time) AS step
   FROM   server_status
   ) d
WHERE  s.server = d.server
AND    s.status = d.status
AND    s.start_time = d.start_time
AND    NOT d.step;

对于8.1。仅在 8.4 中测试。

DELETE FROM server_status s
WHERE (   
   SELECT s1.status = s.status
   FROM   server_status s1
   WHERE  s1.server = s.server
   AND    s1.start_time < s.start_time
   ORDER  BY s1.start_time DESC
   LIMIT  1
   );

(server, start_time) 上的任何 索引 都将大大提高大型表的性能,对于这些查询中的任何

需要升级,仅出于安全原因。 (但为什么要停在 8.4?直接进入当前版本。

【讨论】:

  • 我总是对 8.1 的东西有点不满。问题是我仍然受到red hat 5的限制,而RH5只支持8.4。升级 postgres 并不是当务之急,所以我们仍然停留在 8.1 上。迁移到 RH6 将是一场噩梦,因此不会很快发生。遗憾的是,如果没有大量工作使其适合 8.1,我无法使用此解决方案。
  • @jasonmclose:你确实又提到了 8.4,对吧?你可以在那里使用它。
  • 是的。我们将在几个月后迁移到 8.4,但我希望在我们仍然使用 8.1 的构建下潜入这个版本
  • @jasonmclose:我放弃并添加了旧版本。
猜你喜欢
  • 2021-12-28
  • 2015-04-17
  • 2016-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
  • 1970-01-01
相关资源
最近更新 更多