我创建一个计算两个时间戳之间差异的选择
这里是代码:(您不必理解下面的表格。只需按照主题进行操作)
(select value from demo.data where id=q.id and key='timestampend')::timestamp
- (select value from demo.data where id=q.id and key='timestampstart')::timestamp) as durata
看看这个例子,如果你想要更容易:
select timestamp_end::timestamp - timestamp_start as duration
这里的结果是:
//" durata"是持续时间
问题是第一个时间戳是2017-06-21,第二个时间是2017-06-22所以我们有1天和几个小时的差异。 我怎么做才能显示结果不像" 1天02:06:41.993657"但是" 26:06:41.993657"没有毫秒(26:06:41)?
更新 我正在测试此查询:
select id as ticketid,
(select value from demo.data where id=q.id and key = 'timestampstart')::timestamp as TEnd,
(select value from demo.data where id=q.id and key = 'timestampend')::timestamp as TStart,
(select
make_interval
(
0,0,0,0, -- years, months, weeks, days
extract(days from duration1)::int * 24 + extract(hours from duration1)::int, -- calculated hours (days * 24 + hours)
extract(mins from duration1)::int, -- minutes
floor(extract(secs from duration1))::int -- seconds, without miliseconds, thus FLOOR()
) as duration1
from
(
(select value from demo.data where id=q.id and key='timestampstart')::timestamp - (select value from demo.data where id=q.id and key='timestampend')::timestamp
) t(duration) as dur
from (select distinct id from demo.data) q
错误是相同的: [错误]错误:语法错误在或附近" ::" id = q.id
时出错数据表是这样的:
答案 0 :(得分:1)
在Postgres中,虽然区间数据类型允许小时值大于23(参见https://www.postgresql.org/docs/9.6/static/functions-formatting.html),但to_char()函数将减少天数,如果将delta值设置为“一天内”,则只需“一小时”它并尝试获得'HH24'的价值。
所以,我最终得到了这样的技巧,将to_char(...)与extract(来自......的'epoch')相结合,然后将concatinated值放到另一个to_char():
with timestamps(ts1, ts2) as (
select
'2017-06-21'::timestamptz,
'2017-06-22 01:03:05.1212'::timestamptz
), res as (
select
round(extract('epoch' from ts2 - ts1) / 3600) as hours,
to_char(ts2 - ts1, 'MI:SS') as min_sec
from timestamps
)
select hours, min_sec, to_char(format('%s:%s', hours, min_sec)::interval, 'HH24:MI:SS')
from res;
结果是:
hours | min_sec | to_char
-------+---------+----------
25 | 03:05 | 25:03:05
(1 row)
您可以定义一个SQL函数,以便更轻松地使用它:
create or replace function extract_hhmmss(timestamptz, timestamptz) returns interval as $$
with delta(i) as (
select
case when $2 > $1 then $2 - $1
else $1 - $2
end
), res as (
select
round(extract('epoch' from i) / 3600) as hours,
to_char(i, 'MI:SS') as min_sec
from delta
)
select
(
case when $2 < $1 then '-' else '' end
|| to_char(format('%s:%s', hours, min_sec)::interval, 'HH24:MI:SS')
)::interval
from res;
$$ language sql stable;
使用示例:
[local]:5432 nikolay@test=# select extract_hhmmss('2017-06-21'::timestamptz, '2017-06-22 01:03:05.1212'::timestamptz);
extract_hhmmss
----------------
25:03:05
(1 row)
Time: 0.882 ms
[local]:5432 nikolay@test=# select extract_hhmmss('2017-06-22 01:03:05.1212'::timestamptz, '2017-06-21'::timestamptz);
extract_hhmmss
----------------
-25:03:05
(1 row)
请注意,如果以相反的顺序提供时间戳,它将会出错,但它并不是很难修复。 //更新:已修复。
答案 1 :(得分:1)
你可以使用EXTRACT
函数并用MAKE_INTERVAL
和一些数学来包装它。它非常简单,因为你将时间戳的每个部分都传递给它:
select
make_interval(
0,0,0,0, -- years, months, weeks, days
extract(days from durdata)::int * 24 + extract(hours from durdata)::int, -- calculated hours (days * 24 + hours)
extract(mins from durdata)::int, -- minutes
floor(extract(secs from durdata))::int -- seconds, without miliseconds, thus FLOOR()
) as durdata
from (
select '2017-06-22 02:06:41.993657'::timestamp - '2017-06-21'::timestamp
) t(durdata);
输出:
durdata
----------
26:06:41
您可以将其包装在一个函数中,以便于使用。
不用担心timestamp - timestamp
精确地将输出返回到几天以上,从而丢失了一些信息,因为即使不同年份的计算仍会返回天数和额外时间部分。
示例:
postgres=# select ('2019-06-22 01:03:05.993657'::timestamp - '2017-06-21'::timestamp) as durdata;
durdata
------------------------
731 days 01:03:05.993657