这可能需要一些重构:
;with Sessions as (
select OriginatorId, State, Duration, ActionLocalTime, Campaign
-- Get an id that will later be used to find the max row per session. Break ties with logical State order.
, row_number() over (order by OriginatorId, ActionLocalTime, case State when 'Login' then 10 when 'Logout' then 30 else 20 end, State) as RowNum
-- Get a Session id for each login
, (select count(*) from Actions where State = 'Login' and OriginatorID = a.OriginatorID and ActionLocalTime <= a.ActionLocalTime) as Session
from Actions a
), Campaigns as (
select OriginatorId, State, Duration, ActionLocalTime, RowNum
-- Get the Campaign for this session
, (select max(Campaign) from Sessions where OriginatorID = s.OriginatorID and Session = s.Session) as Campaign
from Sessions s
)
select Campaign
, OriginatorID as Originator
, min(ActionLocalTime) as Start
, (select ActionLocalTime from Sessions where RowNum = max(c.RowNum) and State = 'Logout') as [End]
, (select sum(Duration) from Campaigns where OriginatorID = c.OriginatorID and Campaign = c.Campaign and State = 'Task 1') as Task1
, (select sum(Duration) from Campaigns where OriginatorID = c.OriginatorID and Campaign = c.Campaign and State = 'Task 2') as Task2
, (select State from Sessions where RowNum = max(c.RowNum)) as LastAction
from Campaigns c
group by OriginatorID, Campaign
order by OriginatorID, Campaign
输出:
Campaign Originator Start End Task1 Task2 LastAction
-------- ---------- ----------------------- ----------------------- ----- ----- ----------
Camp1 1000 2013-05-06 08:00:00.000 2013-05-06 09:27:00.000 3120 855 Logout
Camp2 1000 2013-05-06 09:30:00.000 2013-05-06 10:32:00.000 1800 135 Logout
这是一个带有一些额外数据的SQL Fiddle 。