Felhasználó által definiált függvények

A felhasználó által definiált függvények újrafelhasználható al lekérdezések, amelyek a lekérdezés részeként definiálhatók (lekérdezés által definiált függvények), vagy az adatbázis metaadatainak (tárolt függvények) részeként tárolhatók. A felhasználó által definiált függvények neven keresztül hívhatók meg, nulla vagy több bemeneti argumentummal vannak ellátva (amelyek lehetnek skalárisak vagy táblázatosak), és egyetlen értéket hoznak létre (amely skaláris vagy táblázatos is lehet) a függvénytörzs alapján.

A felhasználó által definiált függvények két kategória egyikéhez tartoznak:

  • Skaláris függvények
  • Táblázatos függvények

A függvény bemeneti argumentumai és kimenete határozza meg, hogy skaláris vagy táblázatos-e, ami pedig meghatározza a használat módját.

A felhasználó által definiált függvények több használatának egyetlen lekérdezésen belüli optimalizálásához lásd: Elnevezett kifejezéseket használó lekérdezések optimalizálása.

Skaláris függvény

  • Nulla bemeneti argumentuma van, vagy az összes bemeneti argumentuma skaláris érték
  • Egyetlen skaláris értéket állít elő
  • Bárhol használható, ahol egy skaláris kifejezés engedélyezve van
  • Csak azt a sorkörnyezetet használhatja, amelyben definiálva van
  • Csak az akadálymentes sémában lévő táblákra (és nézetekre) hivatkozhat

Táblázatos függvény

  • Egy vagy több táblázatos bemeneti argumentumot és nulla vagy több skaláris bemeneti argumentumot fogad el, és/vagy:
  • Egyetlen táblázatos értéket hoz létre

Függvények neve

Az érvényes felhasználó által definiált függvényneveknek ugyanazokat az azonosítóelnevezési szabályokat kell követnie, mint a többi entitásnak.

A névnek egyedinek kell lennie a definíció hatókörében is.

Megjegyzés

Ha egy tárolt függvény és egy tábla is ugyanazzal a névvel rendelkezik, akkor a névre mutató hivatkozások a tárolt függvényre, nem pedig a tábla nevére lesznek feloldva. Használja a table függvényt a táblára való hivatkozáshoz.

Bemeneti argumentumok

A felhasználó által definiált érvényes függvények az alábbi szabályokat követik:

  • A felhasználó által definiált függvények szigorúan beírt, nulla vagy több bemeneti argumentumot tartalmazó listával rendelkezik.
  • A bemeneti argumentumok neve, típusa és (skaláris argumentumok esetén) egy alapértelmezett érték.
  • A bemeneti argumentum neve egy azonosító.
  • A bemeneti argumentum típusa vagy a skaláris adattípusok egyike, vagy táblázatos séma.

A bemeneti argumentumok listája szintaktikailag az argumentumdefiníciók vesszővel tagolt listája, zárójelbe csomagolva. Minden argumentumdefiníció a következőképpen van megadva:

ArgName:ArgType [= ArgDefaultValue]

Táblázatos argumentumok esetén az ArgType szintaxisa megegyezik a tábladefiníció szintaxisával (zárójel és az oszlopnév/típuspárok listája), egy " (*) bármely táblázatos séma" kifejezéssel.

Például:

Syntax Bemeneti argumentumok listaleírása
() Nincsenek argumentumok
(s:string) Egy skaláris argumentum, amelynek az a neve s , hogy egy típusú értéket vesz fel string
(a:long, b:bool=true) Két skaláris argumentum, amelyek közül a második alapértelmezett értékkel rendelkezik
(T1:(*), T2(r:real), b:bool) Három argumentum (két táblázatos argumentum és egy skaláris argumentum)

Megjegyzés

Ha táblázatos bemeneti argumentumokat és skaláris bemeneti argumentumokat is használ, helyezze az összes táblázatos bemeneti argumentumot a skaláris bemeneti argumentumok elé.

Példák

Skaláris függvény

let Add7 = (arg0:long = 5) { arg0 + 7 };
range x from 1 to 10 step 1
| extend x_plus_7 = Add7(x), five_plus_seven = Add7()

Táblázatos függvény argumentumok nélkül

let tenNumbers = () { range x from 1 to 10 step 1};
tenNumbers
| extend x_plus_7 = x + 7

Táblázatos függvény argumentumokkal

let MyFilter = (T:(x:long), v:long) {
  T | where x >= v
};
MyFilter((range x from 1 to 10 step 1), 9)

Kimenet

x
9
10

Táblázatos függvény, amely táblázatos bemenetet használ, és nincs megadva oszlop. Bármely tábla átadható egy függvénynek, és a függvényen belül nem lehet táblaoszlopra hivatkozni.

let MyDistinct = (T:(*)) {
  T | distinct *
};
MyDistinct((range x from 1 to 3 step 1))

Kimenet

x
1
2
3

Felhasználó által definiált függvények deklarálása

A felhasználó által definiált függvény deklarációja a következőket biztosítja:

  • Függvény neve
  • Függvényséma (az általa elfogadott paraméterek, ha vannak ilyenek)
  • Függvény törzse

Megjegyzés

A túlterhelési függvények nem támogatottak. Nem hozhat létre több függvényt ugyanazzal a névvel és különböző bemeneti sémákkal.

Tipp

A Lambda-függvények nem rendelkeznek névvel, és let utasítással vannak egy névhez kötve. Ezért ezek felhasználó által definiált tárolt függvényekként tekinthetők. Példa: Egy lambda függvény deklarációja, amely két argumentumot fogad el (egy string nevű s és egy long nevű i). Az első (számmá alakítás után) és a második szorzatát adja vissza. A lambda a névhez fvan kötve:

let f=(s:string, i:long) {
    tolong(s) * i
};

A függvény törzse a következőket tartalmazza:

  • Pontosan egy kifejezés, amely a függvény visszatérési értékét adja meg (skaláris vagy táblázatos érték).
  • A let utasítások tetszőleges száma (nulla vagy több), amelynek hatóköre a függvény törzsének hatóköre. Ha meg van adva, a let utasításoknak meg kell előzniük a függvény visszatérési értékét meghatározó kifejezést.
  • A lekérdezésparaméter-utasítások tetszőleges száma (nulla vagy több), amely deklarálja a függvény által használt lekérdezési paramétereket. Ha meg van adva, akkor meg kell előzniük a függvény visszatérési értékét meghatározó kifejezést.

Megjegyzés

A lekérdezés felső szintjén támogatott egyéb lekérdezési utasítások nem támogatottak a függvénytörzsben. A két utasítást pontosvesszővel kell elválasztani.

Példák felhasználó által definiált függvényekre

Az alábbi szakasz példákat mutat be a felhasználó által definiált függvények használatára.

Let utasítást használó, felhasználó által definiált függvény

Az alábbi példa egy felhasználó által definiált függvényt (lambda) mutat be, amely elfogadja az ID nevű paramétert. A függvény a Test névhez van kötve, és három let utasítást használ, amelyekben a Test3 definíció az ID paramétert használja. Futtatáskor a lekérdezés kimenete 70:

let Test = (id: int) {
  let Test2 = 10;
  let Test3 = 10 + Test2 + id;
  let Test4 = (arg: int) {
      let Test5 = 20;
      Test2 + Test3 + Test5 + arg
  };
  Test4(10)
};
range x from 1 to Test(10) step 1
| count

Felhasználó által definiált függvény, amely egy paraméter alapértelmezett értékét határozza meg

Az alábbi példa egy függvényt mutat be, amely három argumentumot fogad el. Az utóbbi kettő alapértelmezett értékkel rendelkezik, és nem kell jelen lennie a hívási helyen.

let f = (a:long, b:string = "b.default", c:long = 0) {
  strcat(a, "-", b, "-", c)
};
print f(12, c=7) // Returns "12-b.default-7"

Felhasználó által definiált függvény meghívása

A felhasználó által definiált függvény meghívásának módja a függvény által várt argumentumoktól függ. Az alábbi szakaszok azt ismertetik, hogyan hívhat meg UDF-et argumentumok nélkül, hogyan hívhat meg egy UDF-et skaláris argumentumokkal, és hogyan hívhat meg egy táblázatos argumentumokkal rendelkező UDF-et.

UDF meghívása argumentumok nélkül

Egy felhasználó által definiált függvény, amely nem vesz fel argumentumokat, és meghívható a nevével, vagy a nevével és egy zárójelben lévő üres argumentumlistával.

// Bind the identifier a to a user-defined function (lambda) that takes
// no arguments and returns a constant of type long:
let a=(){123};
// Invoke the function in two equivalent ways:
range x from 1 to 10 step 1
| extend y = x * a, z = x * a()
// Bind the identifier T to a user-defined function (lambda) that takes
// no arguments and returns a random two-by-two table:
let T=(){
  range x from 1 to 2 step 1
  | project x1 = rand(), x2 = rand()
};
// Invoke the function in two equivalent ways:
// (Note that the second invocation must be itself wrapped in
// an additional set of parentheses, as the union operator
// differentiates between "plain" names and expressions)
union T, (T())

UDF meghívása skaláris argumentumokkal

Egy felhasználó által definiált függvény, amely egy vagy több skaláris argumentumot vesz fel, a függvény nevével és egy zárójelben megadott konkrét argumentumlistával hívható meg:

let f=(a:string, b:string) {
  strcat(a, " (la la la)", b)
};
print f("hello", "world")

UDF meghívása táblázatos argumentumokkal

Egy felhasználó által definiált függvény, amely egy vagy több táblaargumentumot vesz fel (tetszőleges számú skaláris argumentummal), és a függvény nevével és egy zárójelben megadott konkrét argumentumlistával hívható meg:

let MyFilter = (T:(x:long), v:long) {
  T | where x >= v
};
MyFilter((range x from 1 to 10 step 1), 9)

Az operátorral invoke egy felhasználó által definiált függvényt is meghívhat, amely egy vagy több táblaargumentumot vesz igénybe, és egy táblát ad vissza. Ez a függvény akkor hasznos, ha a függvény első konkrét táblaargumentuma az invoke operátor forrása:

let append_to_column_a=(T:(a:string), what:string) {
    T | extend a=strcat(a, " ", what)
};
datatable (a:string) ["sad", "really", "sad"]
| invoke append_to_column_a(":-)")

Alapértelmezett értékek

A függvények az alábbi feltételek mellett adhatnak alapértelmezett értékeket néhány paraméterüknek:

  • Az alapértelmezett értékek csak a skaláris paraméterekhez adhatók meg.
  • Az alapértelmezett értékek mindig konstansok (állandók). Nem lehetnek tetszőleges számítások.
  • Az alapértelmezett értékkel nem rendelkező paraméterek mindig megelőzik az alapértelmezett értékkel rendelkező paramétereket.
  • A hívóknak minden olyan paraméter értékét meg kell adniuk, amelynek nincsenek alapértelmezett értékei ugyanabban a sorrendben elrendezve, mint a függvénydeklaráció.
  • A hívóknak nem kell megadniuk az alapértelmezett értékekkel rendelkező paraméterek értékét, de ezt megtehetik.
  • A hívók olyan sorrendben adhatnak meg argumentumokat, amelyek nem felelnek meg a paraméterek sorrendjének. Ha igen, el kell nevezniük az argumentumaikat.

Az alábbi példa egy táblát ad vissza két azonos rekorddal. A első hívásában faz argumentumok teljesen "össze vannak firkálva", így mindegyiknek explicit módon nevet ad:

let f = (a:long, b:string = "b.default", c:long = 0) {
  strcat(a, "-", b, "-", c)
};
union
  (print x=f(c=7, a=12)), // "12-b.default-7"
  (print x=f(12, c=7))    // "12-b.default-7"

Kimenet

x
12-b.default-7
12-b.default-7

Függvények megtekintése

A felhasználó által definiált függvények, amelyek nem vesznek fel argumentumokat, és táblázatos kifejezést ad vissza, nézetként jelölhetők meg. A felhasználó által definiált függvények nézetként való megjelölése azt jelenti, hogy a függvény táblázatként viselkedik, amikor helyettesítő karakteres táblanévfeloldás történik.

Az alábbi példa két felhasználó által definiált függvényt mutat be, és T_notviewazt mutatja be, T_view hogy csak az elsőt oldja fel a helyettesítő karakteres hivatkozás a unionkövetkezőben:

let T_view = view () { print x=1 };
let T_notview = () { print x=2 };
union T*

Korlátozások

Az alábbi korlátozások érvényesek:

  • A felhasználó által definiált függvények nem adhatnak át olyan toscalar() hívási információkat, amelyek attól a sorkörnyezettől függenek, amelyben a függvényt meghívják.
  • A táblázatos kifejezéseket visszaadó, felhasználó által definiált függvények nem hívhatók meg olyan argumentummal, amely a sorkörnyezettől függően változik.
  • Egy legalább egy táblázatos bemenetet tartalmazó függvény nem hívható meg távoli fürtön.
  • A skaláris függvények nem hívhatók meg távoli fürtön.

A felhasználó által definiált függvények csak akkor hívhatók meg a sorkörnyezettől függően változó argumentummal, ha a felhasználó által definiált függvény csak skaláris függvényekből áll, és nem használja a függvényt toscalar().

Példák

Támogatott skaláris függvény

A következő lekérdezés azért támogatott, mert f egy skaláris függvény, amely nem hivatkozik táblázatos kifejezésre.

let Table1 = datatable(xdate:datetime)[datetime(1970-01-01)];
let Table2 = datatable(Column:long)[1235];
let f = (hours:long) { now() + hours*1h };
Table2 | where Column != 123 | project d = f(10)

A következő lekérdezés támogatott, mert f egy skaláris függvény, amely a táblázatos kifejezésre Table1 hivatkozik, de az aktuális sorkörnyezetre f(10)való hivatkozás nélkül van meghívva:

let Table1 = datatable(xdate:datetime)[datetime(1970-01-01)];
let Table2 = datatable(Column:long)[1235];
let f = (hours:long) { toscalar(Table1 | summarize min(xdate) - hours*1h) };
Table2 | where Column != 123 | project d = f(10)

Nem támogatott skaláris függvény

A következő lekérdezés nem támogatott, mert f egy skaláris függvény, amely a táblázatos kifejezésre Table1hivatkozik, és az aktuális sorkörnyezetre f(Column)mutató hivatkozással hívja meg:

let Table1 = datatable(xdate:datetime)[datetime(1970-01-01)];
let Table2 = datatable(Column:long)[1235];
let f = (hours:long) { toscalar(Table1 | summarize min(xdate) - hours*1h) };
Table2 | where Column != 123 | project d = f(Column)

Nem támogatott táblázatos függvény

A következő lekérdezés nem támogatott, mert f egy olyan táblázatos függvény, amely olyan környezetben van meghívva, amely skaláris értéket vár.

let Table1 = datatable(xdate:datetime)[datetime(1970-01-01)];
let Table2 = datatable(Column:long)[1235];
let f = (hours:long) { range x from 1 to hours step 1 | summarize make_list(x) };
Table2 | where Column != 123 | project d = f(Column)

A felhasználó által definiált függvények által jelenleg nem támogatott funkciók

A teljesség érdekében íme néhány általánosan kért funkció a felhasználó által definiált függvényekhez, amelyek jelenleg nem támogatottak:

  1. Függvények túlterhelése: Jelenleg nem lehet túlterhelni egy függvényt (így több függvényt is létrehozhat ugyanazzal a névvel és különböző bemeneti sémával).

  2. Alapértelmezett értékek: A függvény skaláris paraméterének alapértelmezett értékének skaláris literálnak (állandónak) kell lennie.