Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Переключайте службы с помощью раскрывающегося списка Версия. Дополнительные сведения о навигации.
Область применения: ✅ Microsoft Fabric ✅ Azure Data Explorer ✅ Azure Monitor ✅ Microsoft Sentinel
Определяемые пользователем функции — это повторно используемые вложенные запросы, которые могут быть определены как часть самого запроса (определяемые запросом функции) или хранятся в составе метаданных базы данных (хранимых функций). Определяемые пользователем функции вызываются с помощью имени, предоставляются с нуля или нескольких входных аргументов (которые могут быть скалярными или табличными) и создают одно значение (которое может быть скалярным или табличным) на основе текста функции.
Определяемая пользователем функция относится к одной из двух категорий:
- Скалярные функции
- Табличные функции
Входные аргументы и выходные данные функции определяют, является ли она скалярной или табличной, которая затем определяет, как она может использоваться.
Чтобы оптимизировать несколько пользовательских функций в одном запросе, см. статью "Оптимизация запросов", использующих именованные выражения.
Мы создали ассортимент определяемых пользователем функций, которые можно использовать в запросах. Дополнительные сведения см. в библиотеке функций.
Скалярная функция
- Имеет нулевые входные аргументы или все входные аргументы являются скалярными значениями
- Создает одно скалярное значение
- Можно использовать везде, где разрешено скалярное выражение
- Может использовать только контекст строки, в котором он определен
- Может ссылаться только на таблицы (и представления), которые находятся в схеме со специальными возможностями
Табличная функция
- Принимает один или несколько табличных входных аргументов, а также ноль или несколько скалярных входных аргументов и/или:
- Создает одно табличное значение
Имена функций
Допустимые имена определяемых пользователем функций должны соответствовать тем же правилам именования идентификаторов , что и другие сущности.
Имя также должно быть уникальным в области определения.
Замечание
Если хранимая функция и таблица имеют одинаковое имя, то любая ссылка на это имя разрешается в хранимую функцию, а не имя таблицы. Используйте функцию таблицы , чтобы ссылаться на таблицу.
Входные аргументы
Допустимые определяемые пользователем функции следуют этим правилам:
- Определяемая пользователем функция имеет строго типизированный список нулевых или более входных аргументов.
- Входной аргумент имеет имя, тип и (для скалярных аргументов) значение по умолчанию.
- Имя входного аргумента — это идентификатор.
- Тип входного аргумента является одним из скалярных типов данных или табличной схемы.
Синтаксически список входных аргументов — это разделенный запятыми список определений аргументов, упакованный в скобки. Каждое определение аргумента указывается как
ArgName:ArgType [= ArgDefaultValue]
Для табличных аргументов ArgType имеет тот же синтаксис, что и определение таблицы (круглые скобки и список пар имени столбца или типа), с добавлением одиночного символа (*) , указывающего "любую табличную схему".
Рассмотрим пример.
| Синтаксис | Описание списка входных аргументов |
|---|---|
() |
Нет аргументов |
(s:string) |
Один скалярный аргумент, называемый s получением значения типа string |
(a:long, b:bool=true) |
Два скалярных аргумента, вторая из которых имеет значение по умолчанию |
(T1:(*), T2:(r:real), b:bool) |
Три аргумента (два табличных аргумента и один скалярный аргумент) |
Замечание
При использовании табличных входных аргументов и скалярных входных аргументов поместите все табличные входные аргументы перед скалярными входными аргументами.
Примеры
Скалярная функция
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()
Табличная функция без аргументов
let tenNumbers = () { range x from 1 to 10 step 1};
tenNumbers
| extend x_plus_7 = x + 7
Табличная функция с аргументами
let MyFilter = (T:(x:long), v:long) {
T | where x >= v
};
MyFilter((range x from 1 to 10 step 1), 9)
Выходные данные
| x |
|---|
| 9 |
| 10 |
Табличная функция, использующая табличные входные данные без указанного столбца. Любую таблицу можно передать в функцию, и столбцы таблицы не могут ссылаться внутри функции.
let MyDistinct = (T:(*)) {
T | distinct *
};
MyDistinct((range x from 1 to 3 step 1))
Выходные данные
| x |
|---|
| 1 |
| 2 |
| 3 |
Объявление определяемых пользователем функций
Объявление определяемой пользователем функции обеспечивает:
- Имя функции
- Схема функции (параметры, которые он принимает, если таковые есть)
- Тело функции
Замечание
Функции перегрузки не поддерживаются. Невозможно создать несколько функций с одинаковым именем и разными входными схемами.
Подсказка
Лямбда-функции не имеют имени и привязаны к имени с помощью инструкции let. Поэтому их можно рассматривать как определяемые пользователем хранимые функции.
Пример: объявление лямбда-функции, которая принимает два аргумента ( string вызываемая s и вызываемая longi). Он возвращает продукт первого (после преобразования его в число) и второй. Лямбда-лямбда привязана к имени f:
let f=(s:string, i:long) {
tolong(s) * i
};
Текст функции включает:
- Ровно одно выражение, которое предоставляет возвращаемое значение функции (скалярное или табличное значение).
- Любое число (ноль или больше) операторов let, область действия которого является частью тела функции. Если задано, операторы let должны предшествовать выражению, определяющему возвращаемое значение функции.
- Любое число (ноль или больше) инструкций параметров запроса, которые объявляют параметры запроса, используемые функцией. Если задано, они должны предшествовать выражению, определяющему возвращаемое значение функции.
Замечание
Другие типы инструкций запросов , поддерживаемые на "верхнем уровне", не поддерживаются в теле функции. Все два оператора должны быть разделены точкой с запятой.
Примеры определяемых пользователем функций
В следующем разделе показаны примеры использования определяемых пользователем функций.
Определяемая пользователем функция, использующая инструкцию let
В следующем примере показана определяемая пользователем функция (лямбда),которая принимает идентификатор с именем параметра. Функция привязана к имени Test и использует три инструкции let , в которых определение Test3 использует параметр ID . При выполнении выходные данные запроса равно 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
Определяемая пользователем функция, определяющая значение по умолчанию для параметра
В следующем примере показана функция, которая принимает три аргумента. Последние два имеют значение по умолчанию и не должны присутствовать на сайте вызова.
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"
Вызов определяемой пользователем функции
Метод вызова определяемой пользователем функции зависит от аргументов, которые функция ожидает получения. В следующих разделах описано, как вызывать UDF без аргументов, вызывать UDF с скалярными аргументами и вызывать UDF с табличными аргументами.
Вызов UDF без аргументов
Определяемая пользователем функция, которая не принимает аргументов и может вызываться по имени или по имени и пустому списку аргументов в скобках.
// 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 с скалярными аргументами
Определяемая пользователем функция, принимающую один или несколько скалярных аргументов, можно вызвать с помощью имени функции и конкретного списка аргументов в скобках:
let f=(a:string, b:string) {
strcat(a, " (la la la)", b)
};
print f("hello", "world")
Вызов UDF с табличными аргументами
Определяемая пользователем функция, которая принимает один или несколько аргументов таблицы (с любым числом скалярных аргументов) и может вызываться с помощью имени функции и конкретного списка аргументов в скобках:
let MyFilter = (T:(x:long), v:long) {
T | where x >= v
};
MyFilter((range x from 1 to 10 step 1), 9)
Оператор также можно использовать invoke для вызова определяемой пользователем функции, которая принимает один или несколько аргументов таблицы и возвращает таблицу. Эта функция полезна, если первый конкретный аргумент таблицы для функции является источником invoke оператора:
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(":-)")
Значения по умолчанию
Функции могут предоставлять значения по умолчанию для некоторых их параметров в следующих условиях:
- Значения по умолчанию могут быть предоставлены только для скалярных параметров.
- Значения по умолчанию — это всегда литералы (константы). Они не могут быть произвольными вычислениями.
- Параметры без значения по умолчанию всегда предшествуют параметрам, имеющим значение по умолчанию.
- Вызывающие должны предоставлять значение всех параметров без значений по умолчанию, расположенных в том же порядке, что и объявление функции.
- Вызывающим абонентам не нужно предоставлять значение параметров со значениями по умолчанию, но это может сделать.
- Вызывающие серверы могут предоставлять аргументы в порядке, который не соответствует порядку параметров. В этом случае они должны назвать свои аргументы.
В следующем примере возвращается таблица с двумя идентичными записями. В первом вызове fаргументы полностью "схватываются", поэтому каждое из них явно присваивается имя:
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"
Выходные данные
| x |
|---|
| 12-b.default-7 |
| 12-b.default-7 |
Функции представления
Определяемая пользователем функция, которая не принимает аргументов и возвращает табличное выражение, можно пометить как представление. Маркировка определяемой пользователем функции как представления означает, что функция ведет себя как таблица при выполнении разрешения имен таблицы подстановочных знаков.
В следующем примере показаны две определяемые пользователем функции, T_view а T_notviewтакже показано, как разрешается только первая из них ссылкой на подстановочные знаки в следующей unionстатье:
let T_view = view () { print x=1 };
let T_notview = () { print x=2 };
union T*
Restrictions
Применяются следующие ограничения:
- Определяемые пользователем функции не могут передавать сведения о вызове toscalar(), зависящие от контекста строки, в котором вызывается функция.
- Определяемые пользователем функции, возвращающие табличное выражение, нельзя вызывать с аргументом, который зависит от контекста строки.
- Функция, принимаюая по крайней мере один табличный ввод, не может вызываться в удаленном кластере.
- Скалярная функция не может вызываться в удаленном кластере.
Единственное место, где определяемая пользователем функция может вызываться с аргументом, который зависит от контекста строки, заключается в том, что определяемая пользователем функция состоит только из скалярных функций и не используется toscalar().
Примеры
Поддерживаемая скалярная функция
Следующий запрос поддерживается, так как f это скалярная функция, которая не ссылается на табличное выражение.
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)
Следующий запрос поддерживается, так как f это скалярная функция, которая ссылается на табличное выражение Table1 , но вызывается без ссылки на текущий контекст f(10)строки:
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)
Неподдерживаемая скалярная функция
Следующий запрос не поддерживается, так как f является скалярной функцией, ссылающейся на табличное выражение Table1, и вызывается ссылкой на текущий контекст f(Column)строки:
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)
Неподдерживаемая табличная функция
Следующий запрос не поддерживается, так как f является табличной функцией, вызываемой в контексте, который ожидает скалярное значение.
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)
Функции, которые в настоящее время не поддерживаются определяемыми пользователем функциями
Для полноты ниже приведены некоторые часто запрашиваемые функции для определяемых пользователем функций, которые в настоящее время не поддерживаются:
Перегрузка функций: в настоящее время нет способа перегрузки функции (способ создания нескольких функций с одинаковым именем и другой входной схемой).
Значения по умолчанию: значение по умолчанию для скалярного параметра функции должно быть скалярным литералом (константой).