我有一张这样的桌子
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个事件,则应采用abs(关闭-打开)之间的时差。
我无法根据“事件”列弄清楚如何做
答案 0 :(得分:3)
这可以使用条件聚合来完成。
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
答案 1 :(得分:1)
简化了@VamsiPrabhala的非常好的答案
task
opened
分组。但是,只有这些任务恰好具有一个closed
和一个event
状态(按此顺序)。通过汇总event
s MIN
,按时间排序,所以第一个(opened
)是MAX
事件,最后一个({{1} })是closed
事件。此外:
两个时间戳之间的时差始终为interval
类型,而不是预期的integer
分钟。要获取会议记录,您需要:
EXTRACT(EPOCH FROM
MAX(time) - MIN(time)
) / 60 as difference
EXTRACT(EPOCH FROM)
将interval
转换为秒。要获得分钟数,请除以60。
答案 2 :(得分:1)
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 :(得分:1)
但是另一个选项是将表分为3个独立的派生表:一个用于opened
事件,一个用于closed
事件,另一个用于“ other”事件(例如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