处理转换

对于未以 Power BI 可直接使用的格式显示数据源响应的情况,可以使用 Power Query 来执行一系列转换。

静态转换

在大多数情况下,数据源以一致的方式呈现数据:给定终结点的列名、数据类型和层次结构是一致的。 在这种情况下,应该始终应用相同的转换集以 Power BI 可接受格式来获取数据。

当数据源被视为标准 REST 服务时,可以在 TripPin 第 2 部分 - REST 服务数据连接器教程中找到静态转换的示例:

let
    Source = TripPin.Feed("https://services.odata.org/v4/TripPinService/Airlines"),
    value = Source[value],
    toTable = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expand = Table.ExpandRecordColumn(toTable, "Column1", {"AirlineCode", "Name"}, {"AirlineCode", "Name"})
in
    expand

此示例中的转换包括:

  1. Source 是从 TripPin.Feed(...) 调用中返回的记录。
  2. 你可以从 Source 的一个键值对中提取值。 键的名称为 value,你可以将结果存储在名为 value 的变量中。
  3. value 是一个可转换为表的列表。 value 中的每个元素都会成为表中的一行,你可以对其调用 toTable
  4. value 中的每个元素本身都是一条记录。 toTable 在单个列中具有所有这些项:"Column1"。 对于 toTable 中的每一行,此步骤都将具有 "AirlineCode" 键的所有数据提取到一个名为 "AirlineCode" 的列中,并将具有 "Name" 键的所有数据提取到一个名为 "Name" 的列中。 "Column1" 被替换为这两个新列。

到头来,剩下的数据采用 Power BI 可以使用并轻松呈现的简单表格格式:

表格形式的数据。

请务必注意,此特异性的静态转换序列只适用于单个终结点。 在上面的示例中,此转换序列仅在 REST 终结点响应中存在 "AirlineCode""Name" 时才起作用,因为它们被硬编码为 M 代码。 因此,如果尝试点击 /Event 终结点,则此转换序列可能不起作用。

将数据推送到导航表可能需要这种高度的特异性,但对于更常规的数据访问函数,建议仅执行适合所有终结点的转换。

注意

请务必在各种数据环境中测试转换。 如果用户在 /airlines 终结点上没有任何数据,那么转换是否会产生一个具有正确架构的空表? 或者,是否在评估期间遇到了错误? 有关单元测试的讨论,请参阅 TripPin 第 7 部分:具有 M 类型的高级架构

动态转换

有时,为了将 API 响应转换为适合 Power BI 数据模型的稳定且一致的形式,需要更复杂的逻辑。

API 响应不一致

基本 M 控制流(if 语句、HTTP 状态代码,try...catch 块等)通常足以处理有少数 API 响应方法的情况。

即时确定架构

某些 API 被设计为必须组合多条信息才能获取正确的表格格式。 请考虑 Smartsheet 的 /sheets 终结点响应,其中包含列名数组和数据行数组。 Smartsheet 连接器能够用以下方式分析此响应:

raw = Web.Contents(...),
columns = raw[columns],
columnTitles = List.Transform(columns, each [title]),
columnTitlesWithRowNumber = List.InsertRange(columnTitles, 0, {"RowNumber"}),
                
RowAsList = (row) =>
    let
        listOfCells = row[cells],
        cellValuesList = List.Transform(listOfCells, each if Record.HasFields(_, "value") then [value]
                else null),
        rowNumberFirst = List.InsertRange(cellValuesList, 0, {row[rowNumber]})
    in
        rowNumberFirst,

listOfRows = List.Transform(raw[rows], each RowAsList(_)),
result = Table.FromRows(listOfRows, columnTitlesWithRowNumber)
  1. 首先处理列标题信息。 你可以title将每个列的记录拉取到列表中,并前置一个你知道将始终表示为此第一列的 RowNumber 列。
  2. 接下来,你可以定义函数,该函数允许将行分析为单元格 value 的列表。 你可以再次前置 rowNumber 信息。
  3. 将你的 RowAsList() 函数应用于 API 响应中返回的每个 row
  4. 将列表转换为表,并指定列标题。