0

理想情况下,我想通过 Power BI 在 Visual Studio Online 中计算由 Product Backlog Items 表示的整个价值流的周期时间。(然后我很想获得每个状态的时间,即它处于“新”状态多长时间,或者它停留在“已提交”状态多长时间。)

首先,我有兴趣使用表示产品积压项目的created date和之间的时间的计算值。closed date在此之后,我热衷于找到找到的值的分布。

product backlog item time between created timestamp to closed timestamp

这将是一个起点,但这当然显示“按标题排队的持续时间分钟”。

大多数其他尝试导致:

无法确定字段之间的关系

有没有办法获得一些周期时间的指示?

4

1 回答 1

1

假设每行都有一个创建日期和关闭日期,您可以使用 power query duration 函数来获取两个日期之间的差异。

https://msdn.microsoft.com/en-us/library/mt296613.aspx

更新:在调查之后(见下面我的评论)我意识到构建你需要的查询需要一些奥林匹克级的查询技能。所以我为你创建了它:)。以下内容适用于 Power BI 桌面,但由于某种原因无法在 PowerBI.com 中刷新(我正在检查)。为此,您需要将您的 VSO 帐户和查询 ID 放入 ConnectionInfo 记录中。

建议设置备用凭据,而不是使用 BASIC 身份验证。

您可以通过将共享查询保存到 VSO 来获取 QueryID,然后使用 curl 使用该查询检索 id:

//Replace YOURACCOUNT and YOURPROJECT with correct values below
curl -u username:password https://YOURACCOUNT.visualstudio.com/DefaultCollection/YOURPROJECT/_apis/wit/queries?$depth=1&api-version=1.0

然后,您可以使用以下查询(创建一个空白查询并将其粘贴到 Power BI Desktop 的高级编辑器中)。您可能需要调整从“workitems =”开始的一些步骤,因为您的查询可能具有与我的不同的字段。如果您返回创建、解决和关闭的日期,我使用的持续时间计算应该适合您。当在 Power BI Desktop 中受到质询时,你将身份验证设置为“基本”并提供所需的凭据。

let
//TODO: replace YOURACCOUNT and YOURQUERYID below 
ConnectionInfo = [account = "YOURACCOUNT.visualstudio.com", queryID="YOURQUERYID"],
account = Record.FieldValues(ConnectionInfo){0},
rootQuery = let
    queryID = Record.FieldValues(ConnectionInfo){1},
    query = "https://" & account & "/DefaultCollection/PowerBIClients/_apis/wit/wiql/" & queryID,
    Source = Json.Document(Web.Contents(query))
in
    Source,

#"INT-columns" = let
    Source = rootQuery,
    columns = Source[columns],
    #"Converted to Table" = Table.FromList(columns, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"referenceName", "name", "url"}, {"referenceName", "name", "url"})
in
    #"Expanded Column1",

#"RAW-workitems" = let
    Source = rootQuery,
    workItems = Source[workItems],
    #"Converted to Table" = Table.FromList(workItems, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "url"}, {"id", "url"})
in
    #"Expanded Column1",

#"INT-columnClause" = let
    Source = #"INT-columns",
    colNames = Table.RemoveColumns(Source,{"name", "url"}),
    list = Table.ToList(colNames),
    joined = Text.Combine(list, ",")
in
    joined,

#"INT-workitemsToGet" = let
    Source = #"RAW-workitems",
    col = Table.RemoveColumns(Source,{"url"}),
    #"Changed Type" = Table.TransformColumnTypes(col,{{"id", type text}}),
    list = Table.ToList(#"Changed Type"),
    l = List.Count(list),
    limits = List.Generate(()=>0, each _ < l, each _ + 100),
    #"Converted to Table" = Table.FromList(limits, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Column1", "iterations"}}),
    #"Added Custom" = Table.AddColumn(#"Renamed Columns", "itemsToGet", each List.Range(list, [iterations], 100)),
    #"Added Custom1" = Table.AddColumn(#"Added Custom", "itemsToGetString", each Text.Combine([itemsToGet], ",")),
    #"Removed Columns" = Table.RemoveColumns(#"Added Custom1",{"iterations", "itemsToGet"})
in
    #"Removed Columns",

#"INT-workitemRequests" = let
    Source = #"INT-workitemsToGet",

    #"Added Custom" = Table.AddColumn(Source, "requests", each "https://" & account & "/DefaultCollection/_apis/wit/workitems?ids=" & [itemsToGetString] & "&fields=" & #"INT-columnClause"),
    #"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"itemsToGetString"})
in
    #"Removed Columns",

workitems = let
    #"INT-workitemsRequests (2)" = let
    Source = #"INT-workitemRequests",
    results = Table.AddColumn(Source, "Results", each Json.Document(Web.Contents([requests]))),
    out = 1
in
    results,
    #"Removed Columns" = Table.RemoveColumns(#"INT-workitemsRequests (2)",{"requests"}),
    #"Expanded Results" = Table.ExpandRecordColumn(#"Removed Columns", "Results", {"count", "value"}, {"Results.count", "Results.value"}),
    #"Expanded Results.value" = Table.ExpandListColumn(#"Expanded Results", "Results.value"),
    #"Expanded Results.value1" = Table.ExpandRecordColumn(#"Expanded Results.value", "Results.value", {"id", "fields", "url"}, {"Results.value.id", "Results.value.fields", "Results.value.url"}),
    #"Expanded Results.value.fields" = Table.ExpandRecordColumn(#"Expanded Results.value1", "Results.value.fields", {"System.Id", "System.WorkItemType", "System.State", "System.AssignedTo", "System.CreatedDate", "System.Title", "Microsoft.VSTS.Common.ResolvedDate", "Microsoft.VSTS.Common.ClosedDate"}, {"System.Id", "System.WorkItemType", "System.State", "System.AssignedTo", "System.CreatedDate", "System.Title", "Microsoft.VSTS.Common.ResolvedDate", "Microsoft.VSTS.Common.ClosedDate"}),
    #"Removed Columns1" = Table.RemoveColumns(#"Expanded Results.value.fields",{"Results.count", "Results.value.id"}),
    #"Renamed Columns" = Table.RenameColumns(#"Removed Columns1",{{"Results.value.url", "WorkItemUrl"}}),
    #"Changed Type" = Table.TransformColumnTypes(#"Renamed Columns",{{"Microsoft.VSTS.Common.ResolvedDate", type datetime}, {"Microsoft.VSTS.Common.ClosedDate", type datetime}, {"System.CreatedDate", type datetime}}),
    #"Added Custom" = Table.AddColumn(#"Changed Type", "DurationToResolved", each Duration.TotalDays([Microsoft.VSTS.Common.ResolvedDate] - [System.CreatedDate])),
    #"Added Custom1" = Table.AddColumn(#"Added Custom", "DurationToClosed", each Duration.TotalDays([Microsoft.VSTS.Common.ClosedDate] - [System.CreatedDate])),
    #"Changed Type1" = Table.TransformColumnTypes(#"Added Custom1",{{"DurationToResolved", type number}, {"DurationToClosed", type number}})
in
    #"Changed Type1"    

in workitems
于 2015-09-19T04:51:28.497 回答