Power BI基于Azure DevOps历史数据计算阻塞时间的技术问询
Calculating Blocked Time for Azure DevOps Work Items in Power BI
Hey there! Let's work through this blocked time calculation for your Azure DevOps data in Power BI—since you're a beginner, I'll break this down step by step with clear DAX code and explanations that match your three scenarios.
Core Problem Recap
You need to calculate total blocked time for each WorkItemId:
- When a row has the "Blocked" tag, count the time from its
AnalyticsUpdatedDateuntil the next non-blocked row (or current date if the item is currently blocked andIsCurrent=True). - Sum all these intervals and write the total to the
BlockedTimecolumn for theIsCurrent=Truerow (or the only row if there's no current record, like WorkItem 149).
Step-by-Step DAX Solution
First, make sure your AnalyticsUpdatedDate is formatted as a DateTime type, and your table is sorted by Index (smallest = most recent revision).
Create a new calculated column named BlockedTime with this DAX code:
BlockedTime = VAR CurrentWorkItem = [WorkItemId] VAR CurrentIsCurrent = [IsCurrent] VAR CurrentDate = NOW() // Use TODAY() if you only need date, not time -- Get all records for the current WorkItem, sorted by Index (most recent first) VAR WorkItemRecords = FILTER( ALL('YourTableName'), -- Replace with your actual table name 'YourTableName'[WorkItemId] = CurrentWorkItem ) VAR SortedRecords = ADDCOLUMNS( WorkItemRecords, "@RowRank", RANKX(WorkItemRecords, [Index],, ASC, DENSE) ) -- Generate unique blocked intervals (avoid double-counting consecutive blocked rows) VAR BlockedIntervals = GENERATE( SortedRecords, VAR IsBlocked = CONTAINSSTRING([TagNames], "Blocked") VAR CurrentUpdateDate = [AnalyticsUpdatedDate] -- Find the next non-blocked record's date (looking back in time, i.e., higher Index) VAR NextUnblockedDate = MAXX( FILTER( SortedRecords, [@RowRank] > EARLIER([@RowRank]) && NOT CONTAINSSTRING([TagNames], "Blocked") ), [AnalyticsUpdatedDate] ) -- Determine the end date of the blocked interval VAR IntervalEndDate = IF( CurrentIsCurrent && IsBlocked, CurrentDate, -- Use current time if item is currently blocked IF(ISBLANK(NextUnblockedDate) && IsBlocked, CurrentDate, NextUnblockedDate) ) -- Only keep the first row of each consecutive blocked segment (to avoid duplicate sums) RETURN IF( IsBlocked && NOT CONTAINSSTRING(LOOKUPVALUE(SortedRecords[TagNames], SortedRecords[@RowRank], [@RowRank]-1), "Blocked"), ROW("@Start", CurrentUpdateDate, "@End", IntervalEndDate), BLANK() ) ) -- Calculate total blocked time by summing all interval durations VAR TotalBlockedDuration = SUMX( BlockedIntervals, DATEDIFF([@Start], [@End], SECOND) -- Swap SECOND with MINUTE/HOUR/DAY for different units ) -- Return total time only for IsCurrent rows or single-record WorkItems RETURN IF( CurrentIsCurrent || COUNTROWS(WorkItemRecords) = 1, TotalBlockedDuration, BLANK() )
How This Works (Matching Your Scenarios)
Let's verify this against your three examples:
Scenario 1: WorkItem 72 (IsCurrent=True, not currently blocked)
- The code identifies two blocked segments:
- From
06/19/2020(Index 1) to06/17/2020(Index 3, first non-blocked row after) - From
06/16/2020(Index 4) to06/15/2020(Index 5, first non-blocked row after)
- From
- The sum of these intervals equals your manual calculation:
(06/19-06/18)+(06/18-06/17)+(06/16-06/15)
Scenario 2: WorkItem 1 (IsCurrent=True, currently blocked)
- Three blocked segments are calculated:
- From
07/07/2020(current row) toCurrentDate - From
07/06/2020(Index9) to07/05/2020(Index10) - From
07/04/2020(Index11) to07/03/2020(Index12)
- From
- The total matches your manual sum of these intervals.
Scenario3: WorkItem149 (only record, blocked, IsCurrent=False)
- Since it's the only record for the WorkItem, the code uses
CurrentDate - 07/02/2020as the total blocked time, which matches your calculation.
Key Notes for Adjustments
- Time Units: Change
SECONDinDATEDIFFtoMINUTE,HOUR, orDAYbased on how you want to measure blocked time. - Tag Matching: If your
TagNamesuses a delimiter (like semicolons for multiple tags),CONTAINSSTRINGstill works to detect "Blocked" anywhere in the string. - Time Zones: If Azure DevOps returns UTC times, add
CONVERT_TIMEZONE([AnalyticsUpdatedDate], "UTC", "Your Time Zone")to adjust dates to your local time. - Performance: For large datasets, replace
ALL('YourTableName')withALLSELECTED('YourTableName')to limit the data being processed.
内容的提问来源于stack exchange,提问作者Swearengen
相关产品推荐
相关产品推荐

