주요 내용으로 건너뛰기

Power Query 함수 및 예제 쿼리

Cognite Data Fusion (REST API) connector for Power BI가 제공하는 함수를 Power Query와 결합하면 Cognite API를 통해 데이터를 가져오고 변환하여 Microsoft Power BIMicrosoft Excel에서 보고서 대시보드를 생성할 수 있습니다.

베타

이 섹션에서 설명하는 기능들은 현재 일부 고객을 대상으로 베타 테스트 중이며 변경될 수 있습니다.

이 페이지의 쿼리 및 Power Query 함수를 복사하여 비즈니스 요구 사항에 맞게 조정하십시오.

유틸리티 함수

Epoch 시간과 타임스탬프 간 변환

CDF 리소스 유형은 _Unix Epoch 기준의 밀리초_를 사용하여 타임스탬프를 예상하고 반환합니다. Power Query에는 이 형식을 datetimezone 유형으로 자동 구문 분석하여 표준 시간대 인식 타임스탬프를 나타내는 방법이 없습니다. CDF 데이터 모델은 기본 필드에 ISO 8601 형식을 사용하여 타임스탬프를 나타냅니다.

다음 함수를 사용하여 datetimezone 변수와 Unix Epoch 기준의 밀리초 간을 변환하고 datetimezone 변수를 ISO 8601 형식의 텍스트로 변환할 수 있습니다.

ConvertDateTimeZoneToMs

Convert datetimezone to milliseconds since epoch
//
(dtz as datetimezone) as number =>
let
// Convert the input DateTimeZone to UTC
UtcDateTime = DateTimeZone.RemoveZone(DateTimeZone.SwitchZone(dtz, 0)),
// Define the Unix epoch start
UnixEpochStart = #datetime(1970, 1, 1, 0, 0, 0),
// Calculate the duration between the input date and Unix epoch start
Delta = UtcDateTime - UnixEpochStart,
// Convert duration to total milliseconds
TotalMilliseconds = Duration.TotalSeconds(Delta) * 1000
in
TotalMilliseconds

ConvertMsToDateTimeZone

Convert milliseconds since epoch to datetimezone
(ms as number) as datetimezone =>
let
// Convert ms to seconds
SecondsSinceEpoch = ms / 1000,

// Create a duration
DurationSinceEpoch = #duration(0, 0, 0, SecondsSinceEpoch),

// Add duration to Unix epoch start to get UTC datetime
UnixEpochStart = #datetime(1970, 1, 1, 0, 0, 0),
UtcDateTime = UnixEpochStart + DurationSinceEpoch,

// Convert UTC datetime to local time zone
LocalDateTimeZone = DateTimeZone.From(UtcDateTime)
in
LocalDateTimeZone

ConvertDateTimeZoneToIso

Convert DateTimeZone to ISO 8601 text representation
(dtz as datetimezone) as text =>
let
// Use DateTimeZone.ToText with ISO 8601 format
Result = DateTimeZone.ToText(dtz, [Format="yyyy-MM-ddTHH:mm:sszzz", Culture="en-US"])
in
Result

함수 추가

Power Query에서 새 함수를 추가하려면 Get Data > Blank Query를 선택하고 함수를 작성하거나 다음 함수 중 하나를 복사하십시오.

시간 델타

시간 델타를 기준으로 시작종료 타임스탬프를 정의하는 것이 일반적입니다. 값은 데이터 집합이 새로 고쳐질 때 업데이트됩니다. 다음 예제에서 EndTime은 현재 시간이고 StartTimeEndTime 7일 전입니다. 이 예제를 수정하여 다른 시간 델타를 사용할 수 있습니다.

Time deltas
CurrentTime = DateTimeZone.LocalNow(),
EndTime = CurrentTime,
StartTime = CurrentTime - #duration(7, 0, 0, 0)

일반적인 GET 요청

CDF REST API connector for Power BIGetCDF 함수를 사용하여 CDF에서 데이터를 가져오는 경우 쿼리 매개 변수를 사용하여 가져올 데이터를 선택하는 필터를 전달해야 합니다.

다음 예에서는 /timeseries 엔드포인트에서 URL에 externalIdPrefixlimit 쿼리 매개 변수를 추가하여 서버 측에서 데이터를 필터링하는 방법을 보여 줍니다.

List all time series instances with an externalId starting with a specific string
let
Source = GetCDF("/timeseries?externalIdPrefix=EVE&limit=1000")
in
Source

일반적인 POST 요청

PostCDF 함수를 사용하여 CDF에서 데이터를 가져오는 경우 가져올 데이터를 선택하는 요청 본문을 작성해야 합니다. 이 함수는 JSON 본문의 텍스트 표현을 수락하지만, Power Query 레코드 데이터 유형을 사용하여 본문을 작성하고 이를 JSON 텍스트 데이터 유형으로 변환한 다음 값을 PostCDF 함수에 전달할 수도 있습니다.

List all data modeling instances for a view using the DMS API
let
SpaceExternalId = "Geography",
ViewExternalId = "City",
ViewVersion = "1",
Body = [
sources = {
[
source = [
type = "view",
space = SpaceExternalId,
externalId = ViewExternalId,
version = ViewVersion
]
]
},
limit = 1000
],
BodyText = Text.FromBinary(Json.FromValue(Body)),
Source = PostCDF("/models/instances/list", BodyText)
in
Source

또는, 수동으로 POST 본문을 텍스트로 작성할 수 있지만 이 경우 큰따옴표(")를 다른 큰따옴표 문자 집합으로 이스케이프 처리해야 합니다.

let
BodyText = "{""sources"": [{""source"": {""type"": ""view"", ""space"": ""Geography"", ""externalId"": ""City"", ""version"": ""1""}}], ""limit"": 1000}",
Source = PostCDF("/models/instances/list", BodyText)
in
Source

POST 요청을 재사용해야 하는 경우 요청을 Power Query 함수로 변환할 수 있습니다. 다음 예를 참조하십시오.

(SpaceExternalId as text, ViewExternalId as text, ViewVersion as text) as table =>
let
Body = [
sources = {
[
source = [
type = "view",
space = SpaceExternalId,
externalId = ViewExternalId,
version = ViewVersion
]
]
},
limit = 1000
],
BodyText = Text.FromBinary(Json.FromValue(Body)),
Source = PostCDF("/models/instances/list", BodyText)
in
Source

Power Query 편집기의 쿼리 목록에서 항목을 마우스 오른쪽 버튼으로 클릭하고 이름 바꾸기를 선택하여 함수 이름을 정의할 수 있습니다.

위의 함수 이름이 ListInstancesDMS라면 Power Query에서 필드 값을 입력하거나 다음과 같은 새 쿼리를 작성하여 새 쿼리에서 함수를 사용할 수 있습니다.

let
Source = ListInstancesDMS("Geography", "City", "1")
in
Source

GraphQL 요청

GraphQL 함수를 사용하여 CDF에서 데이터를 가져오는 경우 특정 데이터 모델에서 가져올 데이터를 선택하는 GraphQL 요청을 작성해야 합니다. 이 함수를 사용하려면 space의 외부 ID, view의 외부 ID, view의 버전, 실행할 GraphQL 쿼리 및 선택적으로 쿼리에 사용할 변수 집합을 지정해야 합니다.

다음 쿼리는 GraphQL 구문을 사용하며 변수를 JSON 텍스트로 전달합니다. 쿼리에서 변수를 사용하면 매개변수화하고 외부 값과 함께 사용하기가 더 쉬워집니다.

List all work orders with an end date greater than a specific date
let
Source = GraphQL(
"cdf_idm",
"CogniteProcessIndustries",
"v1",
"query MyQuery($cursor: String, $endTime: Timestamp) {#(lf) listCogniteMaintenanceOrder(#(lf) first: 1000#(lf) after: $cursor#(lf) filter: {endTime: {gte: $endTime}}#(lf) ) {#(lf) items {#(lf) name#(lf) type#(lf) startTime#(lf) endTime#(lf) priority#(lf) }#(lf) pageInfo {#(lf) endCursor#(lf) hasNextPage#(lf) }#(lf) }#(lf)}",
"{""endTime"": ""2024-10-01T00:00:00+02:00""}"
)
in
Source

현재 Power Query에서 사용하는 M 언어는 여러 줄 문자열을 지원하지 않으므로 쿼리를 한 줄로 작성해야 합니다. #(lf)는 줄 바꿈 문자를 나타냅니다. 위의 예에서는 쿼리를 Power Query의 텍스트 영역 필드에 붙여넣고 변수를 JSON 텍스트로 전달했습니다. Power BI가 원래 쿼리에 줄 바꿈을 추가하여 한 줄 텍스트 변수로 표현한 것을 확인할 수 있습니다.

다른 방법으로, 쿼리를 여러 개의 한 줄 텍스트로 작성하고 Text.Combine 함수를 사용하여 쿼리에 줄 바꿈을 추가할 수 있습니다. 변수를 Power Query 레코드로 정의하고 이를 JSON 텍스트로 변환한 다음 GraphQL 함수에 전달할 수 있습니다. 예를 들어, ConvertDateTimeZoneToIso 함수가 datetimezone 변수를 ISO 8601 형식의 텍스트 표현으로 변환한 다음 이를 쿼리에 변수로 전달하는 방법을 확인해 보십시오.

let
// This could be a parameter or referenced from another query
EndTime = #datetimezone(2024, 10, 1, 0, 0, 0, 2, 0),
VariablesRecord = [
endTime = ConvertDateTimeZoneToIso(EndTime)
],
VariablesText = Text.FromBinary(Json.FromValue(VariablesRecord)),
Query = Text.Combine({
"query MyQuery($cursor: String, $endTime: Timestamp) {",
" listCogniteMaintenanceOrder(",
" first: 1000",
" after: $cursor",
" filter: {endTime: {gte: $endTime}}",
" ) {",
" items {",
" name",
" type",
" startTime",
" endTime",
" priority",
" }",
" pageInfo {",
" endCursor",
" hasNextPage",
" }",
" }",
"}"
}, "#(lf)"),
Data = GraphQL(
"cdf_idm",
"CogniteProcessIndustries",
"v1",
Query,
VariablesText
)
in
Data

고급 예

Cognite API 응답의 형태에 따라, 데이터를 가져오고 변환하려면 추가적인 Power Query 변환이 필요할 수 있습니다. 다음 예를 복사하여 비즈니스 요구 사항에 맞게 조정하십시오.

PostCDF 함수를 사용하여 시퀀스 행 가져오기

다음 Power Query 함수는 CDF에서 시퀀스 외부 ID에 대한 시퀀스 행 데이터를 가져와서 처리합니다. POST 요청을 전송하고, 열 정보를 추출하고, 중첩된 응답 데이터를 확장한 후 테이블 형식으로 재구성합니다. 이 함수는 데이터 유형 변환을 처리하고 불필요한 필드를 제거하며 행별로 데이터를 그룹화합니다. 최종 출력은 올바르게 형식화된 열이 있는 잘 구조화된 테이블입니다.

Fetch sequence rows with PostCDF
(externalId as text) as table =>
let
RequestBody = "{""externalId"": """ & externalId & """, ""limit"": 10000}",
Response = PostCDF("/sequences/data/list", RequestBody),
// Extract columns information from the first page
FirstPage = Response{0},
Columns = FirstPage[columns],
ColumnNames = List.Transform(Columns, each [externalId]),
ColumnTypes = List.Transform(Columns, each
if [valueType] = "STRING" then type text else
if [valueType] = "DOUBLE" then type number else
if [valueType] = "LONG" then Int64.Type
else type any
),
// Extract the 'values' from each row
Rows = Table.ExpandListColumn(Response, "rows"),
ValuesTable = Table.ExpandRecordColumn(Rows, "rows", {"rowNumber", "values"}, {"rows.rowNumber", "rows.values"}),
RemoveColumns = Table.RemoveColumns(ValuesTable,{"id", "externalId", "columns", "nextCursor"}),
ExpandValues = Table.ExpandListColumn(RemoveColumns, "rows.values"),
// Group by rowNumber and create a record for each row
GroupedRows = Table.Group(ExpandValues, {"rows.rowNumber"}, {
{"RowData", (t) => Record.FromList(t[rows.values], ColumnNames)}
}),
// Expand the RowData column
ExpandRows = Table.ExpandRecordColumn(GroupedRows, "RowData", ColumnNames),
// Set column data types
FinalTable = Table.TransformColumnTypes(ExpandRows, List.Zip({ColumnNames, ColumnTypes}))
in
FinalTable

이 함수를 사용하려면 다음과 같이 하십시오.

let
Source = RetrieveSequenceRows("sequence-externalId")
in
Source

PostCDF 함수를 사용하여 DMS 쿼리 엔드포인트에서 인스턴스 가져오기

다음 Power Query 함수는 DMS 쿼리에 대한 데이터 모델링 인스턴스를 검색하고 처리합니다. 이 함수는 응답을 페이지 매김하고 인스턴스를 추출한 다음 중첩된 데이터를 확장합니다.

Fetch instances from the DMS query endpoint with PostCDF
(query as text) as table =>
let
FetchPage = (query as text, optional cursors as nullable record) as table =>
let
Query = Json.Document(query),
UpdatedQuery =
if cursors <> null then
let
// Get all field names of both records
QueryWithFields = Record.FieldNames(Query[with]),
QUerySelectFields = Record.FieldNames(Query[select]),
CursorsFields = Record.FieldNames(cursors),
// Find the intersection of field names
CommonFields = List.Intersect({QueryWithFields, QUerySelectFields, CursorsFields}),
// Create new records containing only the common fields
UpdatedQueryWithAndSelect = Record.TransformFields(
Query,
{
{"with", each Record.SelectFields(_, CommonFields)},
{"select", each Record.SelectFields(_, CommonFields)}
}
)
in
UpdatedQueryWithAndSelect
else
Query,
// Add cursors if they are provided
UpdatedQueryWithCursors =
if cursors <> null then
Record.AddField(UpdatedQuery, "cursors", cursors)
else
UpdatedQuery,
FinalBody = Text.FromBinary(Json.FromValue(UpdatedQueryWithCursors)),
Response = PostCDF("/models/instances/query", FinalBody)
in
Response,
// Helper function to create next cursor record from result table
CreateNextCursorRecordFromTable = (inputTable as table) as record =>
let
RecordsList = List.Transform(
Table.ToRecords(inputTable), each Record.FromList({[nextCursor]}, {[resultExpression]})
),
CombinedRecord = Record.Combine(RecordsList)
in
CombinedRecord,
// Helper function to check if all cursors are null
AllCursorsNull = (cursorsRecord as record) as logical =>
let
CursorValues = Record.ToList(cursorsRecord),
NullCount = List.Count(List.Select(CursorValues, each _ = null))
in
NullCount = List.Count(CursorValues),
// Helper function to aggregate items from all pages and convert to tables
AggregateResults = (results as list) as table =>
let
// Combine all tables
CombinedTable = Table.Combine(results),
// Group by resultExpression and convert items to tables
GroupedTable = Table.Group(
CombinedTable,
{"resultExpression"},
{
{
"items",
each
Table.FromRecords(
List.Combine(List.Transform([items], each if Value.Is(_, type list) then _ else {
_
}))
),
type table
}
}
)
in
GroupedTable,
// Main pagination logic
FetchAllPages = () as list =>
let
// Initialize accumulator
InitialAcc = [
results = {},
currentCursors = null,
hasMore = true
],
// Pagination function
PaginationFunction = (acc as record) =>
let
CurrentPage = FetchPage(query, acc[currentCursors]),
NextCursors = CreateNextCursorRecordFromTable(CurrentPage),
HasMoreResults = not AllCursorsNull(NextCursors) and Table.RowCount(CurrentPage) > 0,
UpdatedResults = List.Combine({acc[results], {CurrentPage}})
in
[
results = UpdatedResults,
currentCursors = NextCursors,
hasMore = HasMoreResults
],
// Keep fetching until no more results
AllResults = List.Generate(
() => InitialAcc, each _[hasMore], each PaginationFunction(_), each _[results]
),
// Get the final list of results
FinalResults = List.Last(AllResults)
in
FinalResults,
// Execute pagination and combine results
AllPages = FetchAllPages(),
FinalTable = AggregateResults(AllPages)
in
FinalTable

이 함수를 사용하려면 다음과 같이 하십시오.

let
Query = [
with = [
cities = [
nodes = [
filter = [
hasData = {
[
space = "Geography",
externalId = "City",
version = "1",
#"type" = "view"
]
}
],
chainTo = "destination",
direction = "outwards"
]
],
countries = [
nodes = [
filter = [
hasData = {
[
space = "Geography",
externalId = "Country",
version = "1",
#"type" = "view"
]
}
],
chainTo = "destination",
direction = "outwards"
]
]
],
select = [
cities = [
sources = {
[
source = [
space = "Geography",
externalId = "City",
version = "1",
#"type" = "view"
],
properties = {
"name"
}
]
}
],
countries = [
sources = {
[
source = [
space = "Geography",
externalId = "Country",
version = "1",
#"type" = "view"
],
properties = {
"name"
}
]
}
]
]
],
QueryText = Text.FromBinary(Json.FromValue(Query)),
Source = QueryDMS(QueryText)
in
Source

위 예제의 hasData 필터와 같은 필터를 추가하여 CDF에서 필요한 인스턴스만 가져오도록 합니다.

PostCDF 함수를 사용하여 시계열 데이터 요소 가져오기

다음 Power Query 함수는 시간 범위 내의 시계열에 대해 집계된 시계열 데이터 요소를 검색하고 처리합니다. 이 함수는 CDF API 요청에 대해 현지 시간대 입력을 UTC로 변환하고, 다중 집계 및 사용자 지정 데이터 단위를 지원하며, 데이터 페이지 매김을 처리합니다. 그런 다음 이 함수는 반환된 UTC 타임스탬프를 다시 현지 시간대로 변환하고 중첩된 API 응답을 확장한 다음 적절하게 형식화된 열이 있는 형식이 잘 지정된 테이블을 출력합니다. 여기에는 현지 타임스탬프와 십진수 집계 값도 포함됩니다.

이 예제에서는 ConvertDateTimeZoneToMsConvertMsToDateTimeZone 함수를 사용하여 타임스탬프를 변환합니다.

(
item as record,
start as datetimezone,
optional end as nullable datetimezone,
optional aggregates as nullable text,
optional granularity as nullable text,
optional targetUnit as nullable text,
optional targetUnitSystem as nullable text,
optional timeZone as nullable text
) =>
let
// Function to detect query type based on item record structure
DetectQueryType = (item as record) =>
let
Fields = Record.FieldNames(item),
HasId = List.Contains(Fields, "id"),
HasExternalId = List.Contains(Fields, "externalId"),
HasSpace = List.Contains(Fields, "space"),
FieldCount = List.Count(Fields),
QueryType =
if HasId and not HasExternalId and not HasSpace and FieldCount = 1 then
"id"
else if HasExternalId and not HasId and not HasSpace and FieldCount = 1 then
"externalId"
else if HasExternalId and HasSpace and not HasId and FieldCount = 2 then
"instanceId"
else
Error.Record(
"Invalid item content", "The item record does not match any supported query type", item
)
in
QueryType,
// Detect query type
queryType = DetectQueryType(item),
// Determine limit based on presence of aggregates
limit = if aggregates <> null then 10000 else 100000,
// Convert aggregates from comma-separated string to list format accepted by the API
AggregatesList = Text.Split(aggregates, ","),
AggregatesTrimmedList = List.Transform(AggregatesList, each Text.Trim(_)),
StartMs = Number.Round(ConvertDateTimeZoneToMs(start)),
EndMs = Number.Round(ConvertDateTimeZoneToMs(end)),
// Function to fetch a single page of data
FetchPage = (cursor as nullable text) =>
let
// Build body item
bodyItem =
if queryType = "id" then
[id = Record.Field(item, "id")]
& (if targetUnit <> null then [targetUnit = targetUnit] else [])
& (if targetUnitSystem <> null then [targetUnitSystem = targetUnitSystem] else [])
& (if cursor <> null then [cursor = cursor] else [])
else if queryType = "externalId" then
[externalId = Record.Field(item, "externalId")]
& (if targetUnit <> null then [targetUnit = targetUnit] else [])
& (if targetUnitSystem <> null then [targetUnitSystem = targetUnitSystem] else [])
& (if cursor <> null then [cursor = cursor] else [])
else if queryType = "instanceId" then
[ instanceId = [ space = Record.Field(item, "space"), externalId = Record.Field(item, "externalId") ] ]
& (if targetUnit <> null then [targetUnit = targetUnit] else [])
& (if targetUnitSystem <> null then [targetUnitSystem = targetUnitSystem] else [])
& (if cursor <> null then [cursor = cursor] else [])
else
error "Invalid query type",
// Build request body
body = [
items = {bodyItem},
limit = limit,
ignoreUnknownIds = true,
start = Text.From(StartMs)
]
& (if end <> null then [end = Text.From(EndMs)] else [])
& (if aggregates <> null then [aggregates = AggregatesTrimmedList] else [])
& (if granularity <> null then [granularity = granularity] else [])
& (if timeZone <> null then [timeZone = timeZone] else []),
Response = PostCDF("/timeseries/data/list", Text.FromBinary(Json.FromValue(body))),
// Try to fetch the cursor from the first item in the response
FirstItem =
if Type.Is(Value.Type(Response), type table) and Table.RowCount(Response) > 0 then
Table.First(Response)
else
null,
NextCursor = if FirstItem <> null then Record.FieldOrDefault(FirstItem, "nextCursor", null) else null,
// Handles empty response and extracts data points when present
FinalItemsList =
if Table.HasColumns(Response, "datapoints") then
let
// Clean up the response table
ColumnsToRemove = {"nextCursor", "isStep", "unit"},
ColumnsPresent = List.Intersect({Table.ColumnNames(Response), ColumnsToRemove}),
CleanedTable = Table.RemoveColumns(Response, ColumnsPresent),
// Expand the "datapoints" column
ExpandedDatapointsList = Table.ExpandListColumn(CleanedTable, "datapoints"),
// Handles the case where the list of "datapoints" is empty
FinalDataPointsList =
if List.NonNullCount(ExpandedDatapointsList[datapoints]) > 0 then
let
// Extract a sample record to determine available fields dynamically
SampleRecord = ExpandedDatapointsList[datapoints]{0},
AvailableFields = Record.FieldNames(SampleRecord),
// Expand the "datapoints" records using the available fields
ExpandedDatapointsRecords = Table.ExpandRecordColumn(
ExpandedDatapointsList, "datapoints", AvailableFields, AvailableFields
),
DataPointsList = Table.ToRecords(ExpandedDatapointsRecords)
in
DataPointsList
else
{}
in
FinalDataPointsList
else
Table.ToRecords(Response)
in
{FinalItemsList, NextCursor},
// Recursive function to accumulate all pages of data
AccumulateData = (cursor as nullable text, accumulatedItems as list) =>
let
CurrentPage = FetchPage(cursor),
NewItems = CurrentPage{0},
NextCursor = CurrentPage{1},
UpdatedAccumulatedItems = accumulatedItems & NewItems,
Result =
if NextCursor <> null then
@AccumulateData(NextCursor, UpdatedAccumulatedItems)
else
UpdatedAccumulatedItems
in
Result,
// Fetch all data
AllItems = AccumulateData(null, {}),
// Convert the accumulated items to a table
ConvertToTable =
if List.IsEmpty(AllItems) then
Table.FromList({}, Splitter.SplitByNothing(), null, null, ExtraValues.Error)
else
Table.FromList(AllItems, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
// Expand the table column and convert timestamps
ExpandedTable =
if not Table.IsEmpty(ConvertToTable) and Table.HasColumns(ConvertToTable, "Column1") then
let
TmpTable = Table.ExpandRecordColumn(
ConvertToTable, "Column1", Record.FieldNames(ConvertToTable{0}[Column1])
),
// timestamp should be always present when there are datapoints
FixType = Table.TransformColumnTypes(TmpTable, {{"timestamp", Int64.Type}}),
ParseTimestamp = Table.TransformColumns(FixType, {"timestamp", each ConvertMsToDateTimeZone(_)}),
ParsedWithType = Table.TransformColumnTypes(ParseTimestamp, {{"timestamp", type datetimezone}}),
// check if the timeseries is of type string
FirstEntry = ParsedWithType{0},
IsString = FirstEntry[isString],
CleanedTable = Table.RemoveColumns(ParsedWithType, {"isString"}),
// Convert aggregate/value columns to decimal number
ValuesAsDecimal =
if aggregates <> null then
Table.TransformColumnTypes(
CleanedTable, List.Transform(AggregatesTrimmedList, each {_, type number})
)
else if IsString then
CleanedTable
else
Table.TransformColumnTypes(
CleanedTable, List.Transform({"value"}, each {_, type number})
),
// Check if "id" column is present and convert to integer
IdAsInteger =
if Table.HasColumns(ValuesAsDecimal, "id") then
Table.TransformColumnTypes(ValuesAsDecimal, {{"id", Int64.Type}})
else
ValuesAsDecimal
in
IdAsInteger
else
ConvertToTable
in
ExpandedTable

이 함수는 이전 예제들보다 훨씬 복잡하며 페이지 매김, 데이터 유형 변환, 중첩된 데이터 확장 등 많은 다양한 시나리오를 처리합니다. 이 함수를 사용하려면 다음과 같이 하십시오.

let
Source = RetrieveDataPoints(
[ externalId = "EVE-TI-FORNEBU-01-3" ],
#datetimezone(2024, 10, 1, 0, 0, 0, 2, 0),
#datetimezone(2024, 10, 13, 10, 0, 0, 2, 0),
"average,max,min",
"1d",
null,
"SI",
"Europe/Oslo"
)
in
Source

이 함수를 기반으로 시계열 외부 ID 목록을 반복 처리하여 결과를 큰 단일 테이블로 결합하는 다른 함수를 만들 수 있습니다. 목록은 다른 테이블의 열일 수 있으며, 이 테이블에서 시계열을 필터링하는 등의 작업을 수행할 수 있습니다. 이 함수를 내부 ID 또는 인스턴스 ID의 목록을 반복 처리하도록 수정할 수 있습니다.

(
externalIds as list,
start as datetimezone,
end as datetimezone,
aggregates as text,
granularity as text,
optional targetUnitSystem as nullable text,
optional timeZone as nullable text
) =>
let
// Iterate over each externalId and get corresponding table
TablesList = List.Transform(
externalIds,
each RetrieveDataPoints(
[ externalId = _ ],
start,
end,
aggregates,
granularity,
null,
targetUnitSystem,
timeZone
)
),
// Combine all tables into one
CombinedTable = Table.Combine(TablesList)
in
CombinedTable

이 함수를 사용하려면 다음과 같이 하십시오.

let
Source = RetrieveDataPointsMultipleTs(
{"EVE-TI-FORNEBU-01-2", "EVE-TI-FORNEBU-01-3"},
#datetimezone(2024, 10, 1, 0, 0, 0, 2, 0),
#datetimezone(2024, 10, 13, 10, 0, 0, 2, 0),
"average,max,min",
"1d",
"SI",
"Europe/Oslo"
)
in
Source
자세히 알아보기