我有一张这样的桌子
Task Event Time
2 opened "2018-12-14 16:23:49.058707+01"
2 closed "2018-12-14 16:24:49.058707+01"
3 opened "2018-12-14 16:25:49.058707+01"
3 Interrupted "2018-12-14 16:26:49.058707+01"
3 closed "2018-12-14 16:27:49.058707+01"
我需要从表中获取类似的数据
Task Difference
2 1
仅当仅打开和关闭2个事件时才应获取数据。如果只有2个事件,那么应该采用abs(关闭 - 打开)之间的时差。
我无法弄清楚如何根据事件列找到它
这可以使用条件聚合来完成。
select task
,max(case when event = 'closed' then time end) - max(case when event = 'opened' then time end) as diff
--The aggregation can also be expressed using FILTER as shown below
--,max(time) FILTER(where event = 'closed') - max(time) FILTER (where event = 'opened')
from tbl
group by task
having count(distinct case when event in ('opened','closed') then event end) = 2
and count(distinct event) = 2
简化了@VamsiPrabhala的非常好的答案
SELECT
task,
MAX(time) - MIN(time) as difference
FROM times
GROUP BY task
HAVING array_agg(event ORDER BY time) = '{"opened","closed"}'
task
分组。但只有这些任务只有一个opened
和一个closed
状态(按此顺序)。通过聚合event
s来检查event
s,按时间排序,第一个(MIN
)是opened
事件,最后一个(MAX
)是closed
事件。此外:
两个时间戳之间的差异总是得到一个interval
类型而不是你预期的integer
分钟。要获得会议记录,您需要:
EXTRACT(EPOCH FROM
MAX(time) - MIN(time)
) / 60 as difference
EXTRACT(EPOCH FROM)
将interval
转换为秒。要得到分钟,除以60。
Vamsi的解决方案有效,但对我的口味来说太复杂了。我会选择:
select task,
max(time) FILTER(where event = 'closed') - max(time) FILTER (where event = 'opened')
from tbl
group by task
having count(*) = 2 and
min(event) = 'closed' and
max(event) = 'opened';
或者,如果我们不想依赖字符串排序:
having count(*) = 2 and
count(*) filter (where event = 'closed') = 1 and
count(*) filter (where event = 'opened') = 1 ;
另一个选择是将你的表分成3个单独的派生表:一个用于opened
事件,一个用于closed
事件,一个用于“其他”事件(例如interrupted
)。然后,您可以将这些派生表连接在一起以获得所需内容。例如(使用CTE,虽然您当然可以内联查询):
WITH
-- sample data
tbl(Task, "Event", Time) AS
(
VALUES
(2, 'opened', '2018-12-14 16:23:49.058707+01'::TIMESTAMP),
(2, 'closed', '2018-12-14 16:24:49.058707+01'::TIMESTAMP),
(3, 'opened', '2018-12-14 16:25:49.058707+01'::TIMESTAMP),
(3, 'interrupted', '2018-12-14 16:26:49.058707+01'::TIMESTAMP),
(3, 'closed', '2018-12-14 16:27:49.058707+01'::TIMESTAMP)
),
-- derived tables
opened AS (SELECT * FROM tbl WHERE "Event" = 'opened'),
closed AS (SELECT * FROM tbl WHERE "Event" = 'closed'),
other AS (SELECT * FROM tbl WHERE "Event" NOT IN ('opened', 'closed'))
SELECT
-- uses @S-Man's EXTRACT function to get minutes from a TIMESTAMP value.
ABS(EXTRACT(epoch FROM (opened.Time - closed.Time)) / 60)
FROM opened
INNER JOIN closed ON
closed.Task = opened.task
-- use LEFT JOIN and NULL to exclude records that have an "other" status.
LEFT JOIN other ON
other.Task = opened.Task
WHERE other.Task IS NULL