Reputation: 11
Data:
SQL Server 2012 - I need to "scan" through a table as shown above and sum up the duration column until the row having "BREAK" in Paycode column.
Then continue to sum up duration column after the "BREAK" row
i.e. i want to get results of
Sum of Duration
---------------
6.08
3.33
I tried this statement, but it's not returning the above desired result:
SELECT duration, paycode, visitstart
INTO #client
FROM VISITS
WHERE visitstart > '2020-01-20'
AND visitstart < '2020-01-21'
AND paycode <> 'BREAK'
ORDER BY VISITSTART, CLIENT_ID
SELECT SUM(duration) AS total_duration, visitstart, paycode
FROM #client
GROUP BY visitstart, paycode
DROP TABLE #client
Please kindly advise
Upvotes: 1
Views: 1166
Reputation: 1081
So,Steve C, I have tried to help you... I have made several cte
Note: if it is last interval then column end_break is replacing by getdate(), just to close interval
and at last we combine our table with breaks_chains Instead of Table type yours Table name
--just get rows with BREAK paycode
with cteBreak as
(
select * from Table where paycode='BREAK'
),
--numbering breaks (=row_numbering() in later version sql server)
breaks_chains as
(
select cte1.visitstart visit_st,count(cte2.visitstart)+1 Num from cteBreak cte1
left join cteBreak cte2
on cte1.visitstart>cte2.visitstart
group by cte1.visitstart
),
--get pairs as "start_break - end_break"
break_interval as
(
select t1.visit_st begin_break, COALESCE(t2.visit_st,getdate()) as end_break,t1.Num from
breaks_chains t1
left join breaks_chains t2
on t2.Num-t1.Num=1
)
select sum(duration) from
(
select duration,paycode,
case
when
(Table.visitstart>break_interval.begin_break
and Table.visitstart<break_interval.end_break)
then break_interval.end_break
when (Table.visitstart<break_interval.begin_break and Num=1)
then break_interval.begin_break
end NumGroup
from Table
left join break_interval
on
(Table.visitstart>break_interval.begin_break
and Table.visitstart<break_interval.end_break)
or
(Table.visitstart<break_interval.begin_break and Num=1) --for first sequence (before first break)
)t
where paycode<>'BREAK'
group by NumGroup
P.S. If you have questions, write it in comments please)
Upvotes: 0
Reputation: 1269973
You can assign groups by summing the number of times that "BREAK" appears. Then you can aggregate. I am not quite sure how the final durations are defined -- in particular whether the "BREAK" row is included. Assuming that it is:
select min(visitstart), max(visitstart),
sum(duration)
from (select t.*,
sum(case when paycode = 'BREAK' then 1 else 0 end) over (order by visitstart) as grp
from t
) t
where paycode <> 'BREAK'
group by grp
Upvotes: 1
Reputation: 37473
Try the below one - it's a gap & island
problem
select sum(duration) as total_duration
from
(
select t.*,
row_number() over (order by visitstart) as seqnum,
row_number() over (partition by case when paycode='Break' then 1 else 0 end order by visitstart) as seqnumt
from yourtablename t
)A
where paycode<>'Break'
group by (seqnum-seqnumt)
Upvotes: 2