Introductie
Microsoft Power Query biedt een krachtige ervaring voor het ophalen van gegevens die veel functies omvat. Een kernmogelijkheid van Power Query is het filteren en combineren van gegevens uit een of meer van een uitgebreide verzameling ondersteunde gegevensbronnen. Dergelijke gegevens mashup wordt uitgedrukt met behulp van de Power Query-formuletaal (informeel bekend als 'M'). Power Query sluit M-documenten in in een breed scala aan Microsoft-producten, waaronder Excel, Power BI, Analysis Services en Dataverse, om herhaalbare mashup van gegevens mogelijk te maken.
Dit document bevat de specificatie voor M. Na een korte inleiding die gericht is op het bouwen van een eerste intuïtieve en vertrouwdheid met de taal, beslaat het document de taal precies in verschillende progressieve stappen:
De lexicale structuur definieert de set teksten die lexicaal geldig zijn.
Waarden, expressies, omgevingen en variabelen, id's en het evaluatiemodel vormen de basisconcepten van de taal.
De gedetailleerde specificatie van waarden, zowel primitieve als gestructureerde, definieert het doeldomein van de taal.
Waarden hebben typen, zelf een speciaal soort waarde, die beide de fundamentele soorten waarden karakteriseren en aanvullende metagegevens bevatten die specifiek zijn voor de vormen van gestructureerde waarden.
De set operators in M bepaalt welke soorten expressies kunnen worden gevormd.
Functions, een ander soort speciale waarden, vormen de basis voor een uitgebreide standaardbibliotheek voor M en maken het toevoegen van nieuwe abstracties mogelijk.
Fouten kunnen optreden bij het toepassen van operators of functies tijdens de evaluatie van expressies. Hoewel fouten geen waarden zijn, zijn er manieren om fouten af te handelen die fouten weer toewijzen aan waarden.
Laat expressies de introductie van hulpdefinities mogelijk maken die worden gebruikt voor het opbouwen van complexe expressies in kleinere stappen.
If-expressies ondersteuning bieden voor voorwaardelijke evaluatie.
Secties een eenvoudig modulariteitsmechanisme bieden. (Secties worden nog niet gebruikt door Power Query.)
Ten slotte verzamelt een geconsolideerde grammatica de grammaticafragmenten van alle andere secties van dit document in één volledige definitie.
Voor computertaaltheoretici: de formuletaal die in dit document is gespecificeerd, is een voornamelijk zuivere, hogere-orde, dynamisch-getypte, gedeeltelijk luie functionele programmeertaal.
De belangrijkste constructie in M is de uitdrukking. Een expressie kan worden geëvalueerd (berekend), wat één waarde oplevert.
Hoewel veel waarden letterlijk als een expressie kunnen worden geschreven, is een waarde geen expressie. De expressie 1
bijvoorbeeld resulteert in de waarde 1; de expressies 1+1
resulteert in de waarde 2. Dit onderscheid is subtiel, maar belangrijk. Expressies zijn recepten voor evaluatie; waarden zijn de resultaten van de evaluatie.
In de volgende voorbeelden ziet u de verschillende soorten waarden die beschikbaar zijn in M. Als conventie wordt een waarde geschreven met behulp van de letterlijke vorm waarin deze worden weergegeven in een expressie die alleen die waarde evalueert. (Houd er rekening mee dat de //
het begin van een opmerking aangeeft die verdergaat met het einde van de regel.)
Een primitieve waarde is een enkele waarde, zoals een getal, logische waarde, tekst of null. Een null-waarde kan worden gebruikt om aan te geven dat er geen gegevens zijn.
123 // A number true // A logical "abc" // A text null // null value
Een lijst waarde is een geordende reeks waarden. M ondersteunt oneindige lijsten, maar als ze als letterlijk zijn geschreven, hebben lijsten een vaste lengte. De accolades
{
en}
duiden het begin en het einde van een lijst aan.{123, true, "A"} // list containing a number, a logical, and // a text {1, 2, 3} // list of three numbers
Een record is een verzameling velden. Een veld is een naam-waardepaar waarbij de naam een tekstwaarde is die uniek is binnen de record van het veld. Met de letterlijke syntaxis voor recordwaarden kunnen de namen zonder aanhalingstekens worden geschreven, een formulier dat ook wel id'swordt genoemd. Hieronder ziet u een record met drie velden met de naam "
A
", "B
" en "C
", met waarden1
,2
en3
.[ A = 1, B = 2, C = 3 ]
Een tabel is een set waarden die zijn ingedeeld in kolommen (die worden aangeduid met de naam) en rijen. Er is geen letterlijke syntaxis voor het maken van een tabel, maar er zijn verschillende standaardfuncties die kunnen worden gebruikt om tabellen te maken op basis van lijsten of records.
Bijvoorbeeld:
#table( {"A", "B"}, { {1, 2}, {3, 4} } )
Hiermee maakt u een tabel met de volgende shape:
Een -functie is een waarde die, wanneer deze wordt aangeroepen met argumenten, een nieuwe waarde produceert. Een functie wordt geschreven door de parameters van de functie weer te geven tussen haakjes, gevolgd door het gaat-naar-symbool
=>
, gevolgd door de expressie die de functie definieert. Deze expressie verwijst doorgaans naar de parameters (op naam).(x, y) => (x + y) / 2`
Het evaluatiemodel van de M-taal wordt gemodelleerd na het evaluatiemodel dat vaak wordt gevonden in spreadsheets, waarbij de volgorde van de berekening kan worden bepaald op basis van afhankelijkheden tussen de formules in de cellen.
Als u formules hebt geschreven in een spreadsheet zoals Excel, herkent u mogelijk de formules aan de linkerkant in de waarden aan de rechterkant wanneer deze worden berekend:
In M kunnen delen van een expressie verwijzen naar andere delen van de expressie op naam en het evaluatieproces bepaalt automatisch de volgorde waarin naar expressies wordt verwezen.
U kunt een record gebruiken om een expressie te produceren die gelijk is aan het vorige spreadsheetvoorbeeld. Wanneer u de waarde van een veld initialiseert, kunt u als volgt verwijzen naar andere velden in de record met behulp van de naam van het veld:
[
A1 = A2 * 2,
A2 = A3 + 1,
A3 = 1
]
De bovenstaande uitdrukking is gelijk aan het volgende (in de zin dat beide tot gelijke waarden evalueren):
[
A1 = 4,
A2 = 2,
A3 = 1
]
Records kunnen zich in andere records bevinden of genest zijn. U kunt de opzoekoperator ([]
) gebruiken om toegang te krijgen tot de velden van een record op naam. De volgende record heeft bijvoorbeeld een veld met de naam Sales
met een record en een veld met de naam Total
dat toegang heeft tot de velden FirstHalf
en SecondHalf
van de Sales
-record:
[
Sales = [ FirstHalf = 1000, SecondHalf = 1100 ],
Total = Sales[FirstHalf] + Sales[SecondHalf]
]
De bovenstaande expressie is gelijk aan het volgende wanneer deze wordt geëvalueerd:
[
Sales = [ FirstHalf = 1000, SecondHalf = 1100 ],
Total = 2100
]
Records kunnen ook worden opgenomen in lijsten. U kunt de positionele indexoperator ({}
) gebruiken om toegang te krijgen tot een item in een lijst met de bijbehorende numerieke index. De waarden in een lijst worden aangeduid met behulp van een op nul gebaseerde index vanaf het begin van de lijst. De indexen 0
en 1
worden bijvoorbeeld gebruikt om te verwijzen naar de eerste en tweede items in de onderstaande lijst:
[
Sales =
{
[
Year = 2007,
FirstHalf = 1000,
SecondHalf = 1100,
Total = FirstHalf + SecondHalf // 2100
],
[
Year = 2008,
FirstHalf = 1200,
SecondHalf = 1300,
Total = FirstHalf + SecondHalf // 2500
]
},
TotalSales = Sales{0}[Total] + Sales{1}[Total] // 4600
]
Lijst- en recordlidexpressies (evenals let-expressies) worden geëvalueerd met behulp van luie evaluatie, wat betekent dat ze alleen worden geëvalueerd als dat nodig is. Alle andere expressies worden geëvalueerd met behulp van gretige evaluatie, wat betekent dat ze onmiddellijk worden geëvalueerd wanneer ze tijdens het evaluatieproces worden aangetroffen. Een goede manier om hier rekening mee te houden is dat het evalueren van een lijst- of recordexpressie een lijst- of recordwaarde retourneert die zelf onthoudt hoe de lijstitems of recordvelden moeten worden berekend, wanneer dit wordt aangevraagd (door opzoek- of indexoperators).
In M is een functie een afbeelding van een set invoerwaarden naar één uitvoerwaarde. Een functie wordt geschreven door eerst de vereiste set invoerwaarden (de parameters voor de functie) een naam te geven en vervolgens een expressie op te geven waarmee het resultaat van de functie wordt berekend met behulp van deze invoerwaarden (de hoofdtekst van de functie) na het symbool 'goes-to' (=>
). Bijvoorbeeld:
(x) => x + 1 // function that adds one to a value
(x, y) => x + y // function that adds two values
Een functie is een waarde, net als een getal of een tekstwaarde. In het volgende voorbeeld ziet u een functie die de waarde is van een veld Toevoegen dat vervolgens wordt aangeroepen, of uitgevoerd, vanuit verschillende andere velden. Wanneer een functie wordt aangeroepen, wordt een set waarden opgegeven die logisch worden vervangen door de vereiste set invoerwaarden in de hoofdtekstexpressie van de functie.
[
Add = (x, y) => x + y,
OnePlusOne = Add(1, 1), // 2
OnePlusTwo = Add(1, 2) // 3
]
M bevat een algemene set definities die beschikbaar zijn voor gebruik vanuit een expressie met de naam standaardbibliotheek, of bibliotheek kortom. Deze definities bestaan uit een set benoemde waarden. De namen van waarden die door een bibliotheek worden geleverd, zijn beschikbaar voor gebruik binnen een expressie zonder expliciet door de expressie te zijn gedefinieerd. Bijvoorbeeld:
Number.E // Euler's number e (2.7182...)
Text.PositionOf("Hello", "ll") // 2
M bevat een set operators die kunnen worden gebruikt in expressies.
Operators worden toegepast op operanden om symbolische expressies te vormen. Bijvoorbeeld, in de expressie 1 + 2
zijn de getallen 1
en 2
operanden en is de operator de operator voor optellen (+
).
De betekenis van een operator kan variëren, afhankelijk van het type waarden dat de operanden hebben. De plus-operator kan bijvoorbeeld worden gebruikt met andere soorten waarden naast getallen:
1 + 2 // numeric addition: 3
#time(12,23,0) + #duration(0,0,2,0)
// time arithmetic: #time(12,25,0)
Een ander voorbeeld van een operator met operand-afhankelijke betekenis is de combinatieoperator (&
):
"A" & "BC" // text concatenation: "ABC"
{1} & {2, 3} // list concatenation: {1, 2, 3}
[ a = 1 ] & [ b = 2 ] // record merge: [ a = 1, b = 2 ]
Houd er rekening mee dat sommige operators niet alle combinaties van waarden ondersteunen. Bijvoorbeeld:
1 + "2" // error: adding number and text isn't supported
Expressies die tijdens het evalueren niet-gedefinieerde operatorvoorwaarden tegenkomen, leiden tot fouten.
metagegevens is informatie over een waarde die is gekoppeld aan een waarde. Metagegevens worden weergegeven als recordwaarde, een metagegevensrecordgenoemd. De velden van een metagegevensrecord kunnen worden gebruikt om de metagegevens voor een waarde op te slaan.
Elke waarde heeft een metagegevensrecord. Als de waarde van de metagegevensrecord niet is opgegeven, is de metagegevensrecord leeg (bevat geen velden).
Metagegevensrecords bieden een manier om aanvullende informatie te koppelen aan elk soort waarde op een onopvallende manier. Als u een metagegevensrecord aan een waarde wilt koppelen, wordt de waarde of het gedrag ervan niet gewijzigd.
Een metagegevensrecordwaarde y
is gekoppeld aan een bestaande waarde x
met behulp van de syntaxis x meta y
. Met de volgende code wordt bijvoorbeeld een metagegevensrecord gekoppeld aan Rating
en Tags
velden met de tekstwaarde "Mozart"
:
"Mozart" meta [ Rating = 5, Tags = {"Classical"} ]
Voor waarden die al een niet-lege metagegevensrecord hebben, is het resultaat van het toepassen van meta het uitvoeren van de recordsamenvoeging van de bestaande en de nieuwe metagegevensrecord. De volgende twee expressies zijn bijvoorbeeld gelijk aan elkaar en aan de vorige expressie:
("Mozart" meta [ Rating = 5 ]) meta [ Tags = {"Classical"} ]
"Mozart" meta ([ Rating = 5 ] & [ Tags = {"Classical"} ])
Een metagegevensrecord kan worden geopend voor een bepaalde waarde met behulp van de functie Value.Metadata. In het volgende voorbeeld opent de expressie in het ComposerRating
veld de metagegevensrecord van de waarde in het Composer
veld en opent vervolgens het Rating
veld van de metagegevensrecord.
[
Composer = "Mozart" meta [ Rating = 5, Tags = {"Classical"} ],
ComposerRating = Value.Metadata(Composer)[Rating] // 5
]
Veel van de voorbeelden die tot nu toe worden weergegeven, bevatten alle letterlijke waarden van de expressie in het resultaat van de expressie. Met de let
-expressie kan een set waarden worden berekend, namen worden toegewezen en vervolgens worden gebruikt in een volgende expressie die volgt op de in
. In ons voorbeeld van verkoopgegevens kunt u bijvoorbeeld het volgende doen:
let
Sales2007 =
[
Year = 2007,
FirstHalf = 1000,
SecondHalf = 1100,
Total = FirstHalf + SecondHalf // 2100
],
Sales2008 =
[
Year = 2008,
FirstHalf = 1200,
SecondHalf = 1300,
Total = FirstHalf + SecondHalf // 2500
]
in Sales2007[Total] + Sales2008[Total] // 4600
Het resultaat van de bovenstaande expressie is een getalwaarde (4600
) die wordt berekend van de waarden die zijn gebonden aan de namen Sales2007
en Sales2008
.
De if
expressie selecteert tussen twee expressies op basis van een logische voorwaarde. Bijvoorbeeld:
if 2 > 1 then
2 + 2
else
1 + 1
De eerste expressie (2 + 2
) is geselecteerd als de logische expressie (2 > 1
) waar is en de tweede expressie (1 + 1
) is geselecteerd als deze onwaar is. De geselecteerde expressie (in dit geval 2 + 2
) wordt geëvalueerd en wordt het resultaat van de if
-expressie (4
).
Een fout is een indicatie dat het proces voor het evalueren van een expressie geen waarde kan opleveren.
Fouten worden gegenereerd door operators en functies die foutvoorwaarden tegenkomen of door de foutexpressie te gebruiken. Fouten worden verwerkt met behulp van de try
-expressie. Wanneer er een fout optreedt, wordt een waarde opgegeven die kan worden gebruikt om aan te geven waarom de fout is opgetreden.
let Sales =
[
Revenue = 2000,
Units = 1000,
UnitPrice = if Units = 0 then error "No Units"
else Revenue / Units
],
UnitPrice = try Number.ToText(Sales[UnitPrice])
in "Unit Price: " &
(if UnitPrice[HasError] then UnitPrice[Error][Message]
else UnitPrice[Value])
In het bovenstaande voorbeeld wordt het Sales[UnitPrice]
-veld geopend en wordt de waarde zodanig opgemaakt dat dit het resultaat oplevert.
"Unit Price: 2"
Als het Units
veld nul was, zou het UnitPrice
veld een fout hebben gegenereerd, die zou zijn verwerkt door de try
. De resulterende waarde zou dan zijn:
"No Units"
Een try
-expressie converteert de juiste waarden en fouten naar een recordwaarde die aangeeft of de try
expressie een fout heeft verwerkt of niet, en de juiste waarde of de foutrecord die is geëxtraheerd bij het verwerken van de fout. Denk bijvoorbeeld aan de volgende expressie die een fout genereert en deze vervolgens meteen afhandelt:
try error "negative unit count"
Deze expressie evalueert naar de volgende geneste recordwaarde, waarin de [HasError]
, [Error]
en [Message]
veldzoekacties in het vorige voorbeeld van de prijs per eenheid worden uitgelegd.
[
HasError = true,
Error =
[
Reason = "Expression.Error",
Message = "negative unit count",
Detail = null
]
]
Een veelvoorkomend geval is het vervangen van fouten door standaardwaarden. De try
-expressie kan worden gebruikt met een optionele otherwise
-component om precies dat in een compacte vorm te bereiken.
try error "negative unit count" otherwise 42
// 42