postgresql查找前后时间戳到任意时间戳

时间:2014-11-25 07:14:03

标签: postgresql

给定一个任意时间戳,例如2014-06-01 12:04:55-04,我可以在某个表格中找到时间戳之前和之后的时间戳。然后,我使用以下查询计算这两者之间经过的秒数:

SELECT EXTRACT (EPOCH FROM (
  (SELECT time AS t0 
    FROM sometable 
    WHERE time < '2014-06-01 12:04:55-04' 
    ORDER BY time DESC LIMIT 1) -
  (SELECT time AS t1
    FROM sometable
    WHERE time > '2014-06-01 12:04:55-04' 
    ORDER BY time ASC LIMIT 1)
)) as elapsedNegative;

` 它有效,但我想知道是否有另一种更优雅或精明的方法来实现相同的结果?我使用的是9.3。这是一个玩具数据库。

CREATE TABLE sometable (
id serial,
time timestamp
);

INSERT INTO sometable (id, time) VALUES (1, '2014-06-01 11:59:37-04');
INSERT INTO sometable (id, time) VALUES (1, '2014-06-01 12:02:22-04');
INSERT INTO sometable (id, time) VALUES (1, '2014-06-01 12:04:49-04');
INSERT INTO sometable (id, time) VALUES (1, '2014-06-01 12:07:35-04');
INSERT INTO sometable (id, time) VALUES (1, '2014-06-01 12:09:53-04');

感谢您的任何提示......

更新感谢@Joe Love和@ClémentPrévost提供了有趣的替代方案。在途中学到了很多东西!

2 个答案:

答案 0 :(得分:1)

如果timestamp列没有索引,此解决方案可能会表现得更好。当9.4出现时,我们可以通过使用聚合过滤器来缩短它。

这应该快一点,因为它运行1次全表扫描而不是2次,但是如果你的时间戳列被索引并且你有一个大数据集,它可能会表现得更糟。

以下是没有纪元转换的示例,使其更易于阅读。

select 
min(
case when start_timestamp > current_timestamp
then
start_timestamp
else 'infinity'::timestamp
end 
),
max(
case when t1.start_timestamp < current_timestamp
then
start_timestamp
else '-infinity'::timestamp
end 
)
 from my_table as t1

这是包括数学和时期提取的例子:

select
extract (EPOCH FROM (
min(
case when start_timestamp > current_timestamp
then
start_timestamp
else 'infinity'::timestamp
end 
)-
max(
case when start_timestamp < current_timestamp
then
start_timestamp
else '-infinity'::timestamp
end 
)))
 from snap.offering_event

如果您需要更多详细信息,请与我们联系 - 我建议您尝试使用我的代码并查看其执行情况。

答案 1 :(得分:1)

鉴于sometable.time列已编制索引,您的原始查询无法更有效,您的执行计划应仅显示2个索引扫描,这非常有效(索引仅在您拥有pg 9.2及更高版本时进行扫描)。 / p>

这是一种更易读的写作方式

WITH previous_timestamp AS (
    SELECT time AS time 
    FROM sometable 
    WHERE time < '2014-06-01 12:04:55-04' 
    ORDER BY time DESC LIMIT 1
), 
next_timestamp AS (
    SELECT time AS time
    FROM sometable
    WHERE time > '2014-06-01 12:04:55-04' 
    ORDER BY time ASC LIMIT 1
)
SELECT EXTRACT (EPOCH FROM (
  (SELECT * FROM next_timestamp) 
  - (SELECT * FROM previous_timestamp)
))as elapsedNegative;

使用CTE,您可以通过命名为子查询赋予意义。显式命名是众所周知且公认的编码最佳实践(使用显式名称,不要缩写,也不要使用通用名称,如“data”或“value”)。

请注意,CTE是优化“围栏”,有时会妨碍计划优化

这是the SQLFiddle

编辑:将提取从CTE移动到最终查询,以便PostgreSQL可以使用仅索引扫描。