Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagesql
with number_of_sprints_to_show as
(
  select  select 6 --how many sprints to show on the chart
  as  as show
),
  
done_statuses as --statuses considered closed/done/completed
(
select 'Done' as dst
),
  
median_average_or_cumulative as
(
select 1 --1=median time in status
         
         --2=average time in status
         
         --3=cumulative time in status
),
  
calculation_logic as
(
select 1 --1=calculate whole time in status (time within a sprint + time ticket spent in status before that (if any))
         
         --2=calculate time in status within particular sprint
),
  
scope as --scope for calculation
(
select * from ticket
),
  
sprints as --selecting last N sprints
(
    selectselect * from sprint
    wherewhere start_date<now()
    orderorder by start_date desc
    limitlimit (select show from number_of_sprints_to_show)
),
  
status_history as --history of statuses
(
  select     select    a.id as workitem_id,
            coalesce            coalesce(b.start,a.created) as start,
            coalesce
            coalesce(b.status,a.status) as status,
            ROW
            ROW_NUMBER() OVER (PARTITION BY workitem_id ORDER BY start asc) as history_id
    fromfrom scope a
    leftleft join tickethistory b on a.id=b.workitem_id and b.field=0
),
  
last_status as --searching for the last status in history for a ticket
(
  select    workitem_id,
            max select    workitem_id,
            max(history_id) as history_id
    fromfrom status_history
    groupgroup by workitem_id
),
  
status_history_with_last as --enrich status_history table with last status info
(
    selectselect a.workitem_id, a.start, a.status, a.history_id, b.history_id as last_status,
    casecase when b.history_id is not null then a.start else null end as last_status_date
    fromfrom status_history a
    leftleft join last_status b on a.workitem_id=b.workitem_id and a.history_id=b.history_id
),
  
sprint_history as --history of sprint assignments
(
    selectselect
            a.id as workitem_id, a.          a.id as workitem_id, a.key, a.summary, a.type, a.priority,
            coalesce
            coalesce(b.start,a.created) as start,
            coalesce
            coalesce(b.sprint,a.sprints::text) as sprint,
            ROW
            ROW_NUMBER() OVER (PARTITION BY workitem_id ORDER BY start asc) as history_id
  from scope from scope a
  left  left join tickethistory b on a.id=b.workitem_id and b.field=1
),
  
sprint_dates as --start & finish dates for sprint assignments
(
select 
  		workitem_id, key, summary, type, priority,
  		id, name, start_date, complete_date,
  		start, finish 
  from
(  
  select 
  		a.workitem_id, a.key, a.summary, a.type, a.priority,
  		s.id, s.name, s.start_date, s.complete_date,
  		greatest(max(b.start),s.start_date) as start,
  		least(min(c.start),coalesce(s.complete_date,now())) as finish
from sprint_history a
join sprints s on a.sprint like '%'||s.id||'%'
left join sprint_history b on a.workitem_id=b.workitem_id and a.history_id>b.history_id and b.sprint not like '%'||s.id||'%'
left join sprint_history c on a.workitem_id=c.workitem_id and a.history_id<c.history_id and c.sprint not like '%'||s.id||'%'
group by a.workitem_id, s.id, s.start_date, s.complete_date, s.name, a.key, a.summary, a.type, a.priority
) as temp
  where finish>start --case when there was a re-asign from a sprint before sprint start date
),
  
final_calculations as --joining sprint dates & statuses to get duration of time spent in each status within each sprint
(
  select
        a
  select
        a.workitem_id, a.key, a.summary, a.type, a.priority,
        a
        a.id, a.name, a.start_date,
        b
        b.status,
        sum
        sum(case when (b.history_id=c.last_status) and (select * from calculation_logic)=1 then --status=current status + logic=1
             DATE_PART('day', 
             DATE_PART('day', a.finish-b.start)
            
            +DATE_PART('hour', a.finish-b.start)/24.0
                        +DATE_PART('minute', a.finish-b.start)/1440.0
        when
        when (b.history_id=c.last_status) and (select * from calculation_logic)=2 then --status=current status + logic=2
             DATE_PART('day', 
             DATE_PART('day', a.finish-greatest(b.start,a.start))
            
            +DATE_PART('hour', a.finish-greatest(b.start,a.start))/24.0
                        +DATE_PART('minute', a.finish-greatest(b.start,a.start))/1440.0
        when
        when (b.history_id!=c.last_status) and (select * from calculation_logic)=1 then --status!=current status + logic=1
             DATE_PART('day', 
             DATE_PART('day', least(c.start,a.finish)-b.start)
            
            +DATE_PART('hour', least(c.start,a.finish)-b.start)/24.0
                        +DATE_PART('minute', least(c.start,a.finish)-b.start)/1440.0
           else                                                                            --status!=current status + logic=1
             DATE_PART('day', least(c.start,a.finish)-greatest(b.start,a.start))
            +DATE_PART('hour', least(c.start,a.finish)-greatest(b.start,a.start))/24.0
            +DATE_PART('minute', least(c.start,a.finish)-greatest(b.start,a.start))/1440.0
        end) as duration
from sprint_dates a
  join status_history b on a.workitem_id=b.workitem_id
    and lower(b.status) not in (select lower(dst) from done_statuses)
    and b.start<=a.finish
  join status_history_with_last c on a.workitem_id=c.workitem_id and
        ((b.history_id+1=c.history_id and c.start>a.start) OR (b.history_id=c.last_status))
  group by a.workitem_id, a.key, a.summary, a.type, a.priority, a.id, a.name, a.start_date, b.status
)
 
select  name as "Sprint Name",          --change statuses below according to your workflow
        case when (select * from median_average_or_cumulative)=1 then (percentile_cont(0.5) WITHIN GROUP (ORDER BY to_do))
             when (select * from median_average_or_cumulative)=2 then avg(to_do)
                                                                 else sum(to_do) end as "To Do",
        case else                                                                            --status!=current status + logic=1
             DATE_PART('day', least(c.start,a.finish)-greatest(b.start,a.start))
            +DATE_PART('hour', least(c.start,a.finish)-greatest(b.start,a.start))/24.0
            +DATE_PART('minute', least(c.start,a.finish)-greatest(b.start,a.start))/1440.0
        end) as duration
from sprint_dates a
  join status_history b on a.workitem_id=b.workitem_id
    and lower(b.status) not in (select lower(dst) from done_statuses)
    and b.start<=a.finish
  join status_history_with_last c on a.workitem_id=c.workitem_id and
        ((b.history_id+1=c.history_id and c.start>a.start) OR (b.history_id=c.last_status))
  group by a.workitem_id, a.key, a.summary, a.type, a.priority, a.id, a.name, a.start_date, b.status
)
 
select  name as "Sprint Name",          --change statuses below according to your workflow
        case when (select * from median_average_or_cumulative)=1 then (percentile_cont(0.5) WITHIN GROUP (ORDER BY to_do))
             when (select * from median_average_or_cumulative)=2 then avg(to_do)
                                                                 else sum(to_do) end as "To Do",
        case when (select * from median_average_or_cumulative)=1 then (percentile_cont(0.5) WITHIN GROUP (ORDER BY selected_for_development))
             when (select * from median_average_or_cumulative)=2 then avg(selected_for_development)
                                                                 else sum(selected_for_development) end as "Selected for Development",
        case when (select * from median_average_or_cumulative)=1 then (percentile_cont(0.5) WITHIN GROUP (ORDER BY blocked))
             when (select * from median_average_or_cumulative)=2 then avg(blocked)
                                                                 else sum(blocked) end as "Blocked",
        case when (select * from median_average_or_cumulative)=1 then (percentile_cont(0.5) WITHIN GROUP (ORDER BY in_progress))
             when (select * from median_average_or_cumulative)=2 then avg(in_progress)
                                                                 else sum(in_progress) end as "In Progress",
        case when (select * from median_average_or_cumulative)=1 then (percentile_cont(0.5) WITHIN GROUP (ORDER BY selectedcode_for_developmentreview))
             when (select *
from median_average_or_cumulative)=2 then avg(selected_for_development)
                                                                 else sum(selected_for_development) end as "Selected for Development",
        case           when (select * from median_average_or_cumulative)=12 then avg(percentile_cont(0.5) WITHIN GROUP (ORDER BY blocked))
             when (select * from median_average_or_cumulative)=2 then avg(blocked)
                                                                 else sum(blocked) end as "Blocked",
        case when (select * from median_average_or_cumulative)=1 then (percentile_cont(0.5) WITHIN GROUP (ORDER BY in_progress))
             when (select * from median_average_or_cumulative)=2 then avg(in_progress)
                                                                 else sum(in_progresscode_review)
                                                                 else sum(code_review) end as "InCode ProgressReview",
        case
        case when (select * from median_average_or_cumulative)=1 then (percentile_cont(0.5) WITHIN GROUP (ORDER BY code_review))
             when review_and_testing))
             when (select * from median_average_or_cumulative)=2 then avg(codereview_and_reviewtesting)
                                                                 else sum(code_review) end as "Code Review",
        case when (select * from median_average_or_cumulative)=1 then (percentile_cont(0.5) WITHIN GROUP (ORDER BY review_and_testing))
             when (select * from median_average_or_cumulative)=2 then avg(review_and_testing)
                                                                 else
                                                                 else sum(review_and_testing) end as "Review and Testing"
from
(
select select  name, start_date, workitem_id,
        case        case when status='To Do' then duration else null end as to_do,
        case
        case when status='Selected for Development' then duration else null end as selected_for_development,
        case
        case when status='Blocked' then duration else null end as blocked,
        case        case when status='In Progress' then duration else null end as in_progress,
        case
        case when status='Code Review' then duration else null end as code_review,
        case
        case when status='Review and Testing' then duration else null end as review_and_testing
from final_calculations
) as temp
group by name, start_date
order by start_date asc

...

Code Block
languagesql
select key, summary, type, priority, "Time in Status (d)" from
(
select key, summary, type, priority, round(duration::numeric,2) as "Time in Status (d)", name
from final_calculations
where status='To Do'
) as temp
where where name=clicked_x_value
order by "Time in Status (d)" desc

...