Fonctions Power Query et exemples de requêtes
Combinez les fonctions (exposées par le Cognite Data Fusion (REST API) connector for Power BI) avec Power Query pour récupérer et transformer des données à l’aide de l’Cognite API, en vue de créer des rapports et des tableaux de bord avec Microsoft Power BI et Microsoft Excel.
Les fonctionnalités décrites dans cette section font actuellement l’objet de tests bêta avec certains clients, et sont susceptibles d’être modifiées.
Copiez et adaptez les requêtes et les fonctions Power Query de cette page aux besoins de votre entreprise.
Fonctions Utility
Conversion d’horodatages depuis/vers l’époque Unix
Les types de ressources CDF s’attendent à recevoir et renvoient des horodatages sous forme de millisecondes depuis l’époque Unix. Power Query n’offre aucune méthode pour analyser automatiquement ce format sous un type datetimezone
afin de représenter les horodatages contenant des informations sur les fuseaux horaires. Les modèles de données CDF représentent les horodatages sous le format ISO 8601 spécifique aux champs primitifs.
Utilisez les fonctions ci-après pour convertir une variable datetimezone
en millisecondes depuis l’époque Unix et convertir une variable datetimezone
en texte au format ISO 8601.
ConvertDateTimeZoneToMs
//
(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
(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
(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
Ajout d’une fonction
Pour ajouter une nouvelle fonction dans Power Query, choisissez Get Data (Obtenir des données) > Blank Query (Requête vierge) et écrivez votre fonction ou copiez l’une des fonctions ci-dessous.
Deltas temps
Il est courant de définir les horodatages début et fin en fonction des deltas temps. Les valeurs sont mises à jour au moment de l’actualisation d’un jeu de données. Dans l’exemple ci-dessous, EndTime
est l’heure actuelle et StartTime
est 7 jours avant EndTime
. Vous pouvez adapter cet exemple pour utiliser différents deltas temps.
CurrentTime = DateTimeZone.LocalNow(),
EndTime = CurrentTime,
StartTime = CurrentTime - #duration(7, 0, 0, 0)
Requête GET classique
Lorsque vous récupérez des données depuis CDF à l’aide de la fonction GetCDF
du CDF REST API connector for Power BI, vous devez utiliser des paramètres de requête pour transmettre les filtres de sélection des données à extraire.
L’exemple ci-dessous montre comment ajouter les paramètres de requête externalIdPrefix
et limit
du point de terminaison /timeseries
à l’URL afin de filtrer les données du côté serveur.
let
Source = GetCDF("/timeseries?externalIdPrefix=EVE&limit=1000")
in
Source
Requête POST classique
Lorsque vous récupérez des données depuis CDF à l’aide de la fonction PostCDF
, vous devez rédiger le corps de la requête pour sélectionner les données à extraire. La fonction accepte une représentation textuelle du corps JSON, mais vous pouvez aussi rédiger le corps à l’aide d’un type d’enregistrement Power Query, puis le convertir en type de données textuelles JSON avant de transmettre la valeur à la fonction PostCDF
.
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
L’autre solution consiste à rédiger manuellement le corps POST sous forme de texte, mais vous devrez utiliser une autre paire de guillemets doubles pour entourer les caractères entre guillemets doubles ("
).
let
BodyText = "{""sources"": [{""source"": {""type"": ""view"", ""space"": ""Geography"", ""externalId"": ""City"", ""version"": ""1""}}], ""limit"": 1000}",
Source = PostCDF("/models/instances/list", BodyText)
in
Source
Si vous avez besoin de réutiliser une requête POST, vous pouvez la transformer dans une fonction Power Query. Par exemple :
(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
Vous pouvez définir le nom de la fonction en cliquant avec le bouton droit sur l’entrée dans la liste des requêtes dans l’éditeur Power Query, puis en choisissant Rename (Renommer).
Si la fonction ci-dessus est appelée ListInstancesDMS
, vous pouvez l’utiliser dans une nouvelle requête en saisissant les valeurs de champ dans Power Query ou en formulant une nouvelle requête :
let
Source = ListInstancesDMS("Geography", "City", "1")
in
Source
Requêtes GraphQL
Lorsque vous récupérez des données depuis CDF à l’aide de la fonction GraphQL
, vous devez formuler une requête GraphQL pour sélectionner les données à extraire d’un modèle de données spécifique. La fonction s’attend à ce que vous indiquiez l’ID externe pour space, l’ID externe pour view, la version de view, la requête GraphQL à exécuter et éventuellement un ensemble de variables à utiliser dans la requête.
La requête ci-après utilise la syntaxe GraphQL et transmet les variables sous forme de textes JSON. L’insertion de variables dans la requête facile la création de requêtes paramétrables et l’utilisation de valeurs externes.
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
Le langage M utilisé par Power Query ne prend pas en charge, pour l’instant, les chaînes composées de plusieurs lignes. Veuillez formuler la requête sur une seule ligne. #(lf)
représente un caractère de saut de ligne. Dans l’exemple ci-dessus, la requête a été collée dans le champ de la zone de texte dans Power Query et les variables ont été transmises sous forme de textes JSON. Remarquez la façon dont Power BI a ajouté des sauts de ligne à la requête d’origine et présenté celle-ci sous la forme d’une variable de texte d’une seule ligne.
L’autre solution consiste à formuler une requête composée de plusieurs lignes de texte et d’utiliser la fonction Text.Combine
pour ajouter des sauts de ligne dans la requête. Vous pouvez définir les variables comme des enregistrementsPower Query et les convertir sous forme de textes JSON avant de les transmettre à la fonction GraphQL
. Découvrez, par exemple, comment la fonction ConvertDateTimeZoneToIso
convertit une variable datetimezone
en représentation textuelle au format ISO 8601, puis transmet cette dernière en tant que variable à la requête.
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
Exemples plus sophistiqués
Selon la forme de la réponse de l’API Cognite, d’autres transformations Power Query peuvent être nécessaires pour récupérer et transformer les données. Copiez et adaptez les exemples ci-après aux besoins de votre entreprise.
Récupération des rangées d’une séquence à l’aide de la fonction PostCDF
La fonction Power Query ci-dessous récupère et traite les données des rangées d’une séquence correspondant à un ID de séquence externe de CDF. Elle envoie une requête POST, extrait les informations des colonnes, développe les données de réponses imbriquées, puis les réorganise sous forme de tableau. La fonction gère la conversion des types de données, élimine les champs inutiles et regroupe les données par rangée. Le résultat final est un tableau parfaitement structuré avec des colonnes complétées correctement.
(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
Pour utiliser la fonction :
let
Source = RetrieveSequenceRows("sequence-externalId")
in
Source
Récupération d’instances du point de terminaison d’une requête DMS à l’aide de la fonction PostCDF
La fonction Power Query ci-après récupère et traite les instances de modélisation des données pour une requête DMS. Elle procède à la pagination de la réponse, extrait les instances, puis développe les données imbriquées.
(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
Pour utiliser la fonction :
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
Ajoutez des filtres tels que le filtre hasData
dans l’exemple ci-dessus pour éviter de récupérer tous les instances de CDF.
Récupération des points de données d’une séries temporelle à l’aide de la fonction PostCDF
La fonction Power Query ci-après récupère et traite des points de données agrégés d’une série temporelle dans une plage de temps donnée. Elle convertit les entrées correspondant à des fuseaux horaires locaux en horodatages UTC pour les requêtes API CDF, prend en charge les agrégats multiples et la granularité personnalisée, et gère la pagination des données. La fonction reconvertit ensuite les horodatages UTC sous forme de fuseau horaire local, développe la réponse API imbriquée, puis génère un tableau bien structuré avec les colonnes correctement complétées. Elle inclut également des horodatages locaux et des valeurs d’agrégat décimales.
Cet exemple tire parti des fonctions ConvertDateTimeZoneToMs
et ConvertMsToDateTimeZone
pour convertir les horodatages.
(
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
La fonction est plus complexe que celles évoquées dans les exemples précédents et gère divers cas de figure, avec pagination, conversion des types de données et développement des données imbriquées. Pour utiliser la fonction :
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
En vous basant sur cette fonction, vous pouvez créer une autre fonction pour appliquer une opération, de façon répétitive, à une liste d’ID externes de séries temporelles et combiner les résultats dans un grand tableau. La liste peut être une colonne d’un autre tableau dans laquelle vous filtrez les séries temporelles, par exemple. Vous pouvez adapter la fonction pour appliquer une opération, de façon répétitive, à une liste d’ID internes ou d’ID d’instances.
(
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
Pour utiliser la fonction :
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
- Microsoft : documentation
Power Query