给定一个任意时间戳,例如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提供了有趣的替代方案。在途中学到了很多东西!
答案 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是优化“围栏”,有时会妨碍计划优化
编辑:将提取从CTE移动到最终查询,以便PostgreSQL可以使用仅索引扫描。