对于未以 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
此示例中的转换包括:
Source
是从TripPin.Feed(...)
调用中返回的记录。- 你可以从
Source
的一个键值对中提取值。 键的名称为value
,你可以将结果存储在名为value
的变量中。 value
是一个可转换为表的列表。value
中的每个元素都会成为表中的一行,你可以对其调用toTable
。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)
- 首先处理列标题信息。 你可以
title
将每个列的记录拉取到列表中,并前置一个你知道将始终表示为此第一列的RowNumber
列。 - 接下来,你可以定义函数,该函数允许将行分析为单元格
value
的列表。 你可以再次前置rowNumber
信息。 - 将你的
RowAsList()
函数应用于 API 响应中返回的每个row
。 - 将列表转换为表,并指定列标题。