我有以下案例情景:
我的表有以下列:ID,ClientName(String),StartTime(时间戳),EndTime(时间戳)。
我的目标是为每个客户加上持续时间,例如对于最后一天,假设在一个时间段内可以是很少的值,我必须只有实际持续时间。
e.g。表内容:
|Client1 | 2017-01-01 08:00:00 | 2017-01-01 08:05:00|
|Client1 | 2017-01-01 08:00:00 | 2017-01-01 08:10:00|
我在这个例子中使用以下查询:
Select ClientName, SUM(date_trunc('second',coalesce(EndTime,now()::timestamp(0))-StartTime)) as duration
from table
group by ClientName
上述查询的结果为15,但应为10.同一时间段不应计算。
如何在PostgreSQL中获得正确的结果?
答案 0 :(得分:0)
你没有提到你正在使用哪个数据库,每个数据库的实现都不同,但逻辑相同,
用于Postgresql 我使用row_number删除不正确的行
select ClientName,
SUM(date_trunc('second',coalesce(EndTime,now()::timestamp(0))-StartTime)) as duration,
SUM(datediff(minute,StartTime,EndTIme)) as Duration2
from(
select ClientName,
StartTime,
EndTIme,
row_number () over ( partition by ClientName,StartTime order by EndTime desc) as rank
from table) a
where rank=1
group by ClientName
答案 1 :(得分:0)
请参考参考Calculate Actual Downtime ignoring overlap in dates/times
DECLARE @clientUsage TABLE (
ID INT PRIMARY KEY NOT NULL IDENTITY(1,1),
ClientName VARCHAR(25),
StartTime DATETIME,
EndTime DATETIME
)
INSERT @clientUsage (ClientName, StartTime, EndTime) VALUES
('client', '2014-11-20 17:31:01.467', '2014-11-20 18:01:01.243')
,('client', '2014-11-28 17:59:00.987', '2014-11-28 18:09:02.167')
,('client', '2014-11-28 18:00:01.403', '2014-11-28 18:25:01.443')
,('client', '2014-11-29 19:13:08.580', '2014-11-30 05:30:01.763')
,('client', '2014-11-30 01:55:01.953', '2014-11-30 03:54:01.730')
,('client 2', '2014-12-19 23:09:01.303', '2014-12-22 09:43:01.397')
,('client 2', '2014-12-19 23:09:01.303', '2014-12-22 09:43:01.397')
,('client 2', '2014-12-19 23:09:01.303', '2014-12-22 09:43:01.397')
,('client 2', '2014-12-19 23:09:01.303', '2014-12-22 09:43:01.397')
,('client 2', '2014-12-19 23:09:01.303', '2014-12-22 09:43:01.397')
如果您使用表而不是临时表
select clientname,sum(actual) from
(SELECT
clienttime.ClientName,
clienttime.StartTime,
clienttime.EndTime,
COALESCE(Actual, 0) AS Actual
FROM @clientUsage clienttime
LEFT OUTER JOIN (
SELECT DISTINCT
D1.ClientName,
MIN(CASE WHEN D1.StartTime < D2.StartTime THEN D1.ID ELSE D2.ID END) AS [ID],
MIN(CASE WHEN D1.StartTime < D2.StartTime THEN D1.StartTime ELSE D2.StartTime END) AS [StartTime],
MAX(CASE WHEN D1.EndTime > D2.EndTime THEN D1.EndTime ELSE D2.EndTime END) AS [EndTime],
DATEDIFF(MINUTE,
MIN(CASE WHEN D1.StartTime < D2.StartTime THEN D1.StartTime ELSE D2.StartTime END),
MAX(CASE WHEN D1.EndTime > D2.EndTime THEN D1.EndTime ELSE D2.EndTime END)) AS Actual
FROM @clientUsage D1
INNER JOIN @clientUsage D2
ON D1.ClientName = D2.ClientName
AND (D1.StartTime BETWEEN D2.StartTime AND D2.EndTime
OR D2.StartTime BETWEEN D1.StartTime AND D1.EndTime)
GROUP BY
D1.ClientName,
D1.StartTime
) Outages
ON Outages.ID = clienttime.ID) op group by clientname
我在sql server中测试过。