Функции, определённые пользователем

Большинство баз данных имеют процедурный диалект SQL, который можно использовать для определения собственных функций. Однако SQLite работает внутри процесса вашего приложения. Вместо того чтобы узнать новый диалект SQL, вы можете просто использовать язык программирования вашего приложения.

Скалярные функции

Скалярные функции возвращают одно скалярное значение для каждой строки в запросе. Определите новые скалярные функции и переопределите встроенные функции с помощью CreateFunction.

Список поддерживаемых параметров и возвращаемых типов для аргумента см. в разделе func".

Указание аргумента state передает это значение во все вызовы функции. Это позволяет избежать закрытия.

Укажите isDeterministic , является ли функция детерминированной, чтобы разрешить SQLite использовать дополнительные оптимизации при компиляции запросов.

В следующем примере показано, как добавить скалярную функцию для вычисления радиуса цилиндра.

connection.CreateFunction(
    "volume",
    (double radius, double height)
        => Math.PI * Math.Pow(radius, 2) * height);

var command = connection.CreateCommand();
command.CommandText =
@"
    SELECT name,
           volume(radius, height) AS volume
    FROM cylinder
    ORDER BY volume DESC
";

Операторы

Следующие операторы SQLite реализуются соответствующими скалярными функциями. Определение этих скалярных функций в приложении переопределяет поведение этих операторов.

Оператор Функция
X ГЛОБ Y glob(Y, X)
X как Y лайк(Y, X)
X LIKE Y ESCAPE Z like(Y, X, Z)
X СООТВЕТСТВИЕ Y match(Y, X)
X REGEXP Y regexp(Y, X)

В следующем примере показано, как определить функцию regexp, чтобы включить соответствующий оператор. SQLite не включает реализацию функции regexp по умолчанию.

connection.CreateFunction(
    "regexp",
    (string pattern, string input)
        => Regex.IsMatch(input, pattern));

var command = connection.CreateCommand();
command.CommandText =
@"
    SELECT count()
    FROM user
    WHERE bio REGEXP '\w\. {2,}\w'
";
var count = command.ExecuteScalar();

Агрегатные функции

Агрегатные функции возвращают одно агрегированное значение для всех строк в запросе. Определение и переопределение агрегатных функций с помощью CreateAggregate.

Аргумент seed указывает начальное состояние контекста. Используйте это, чтобы избежать закрытий.

Аргумент func вызывается один раз в каждой строке. Используйте контекст для получения окончательного результата. Возвращает контекст. Этот шаблон позволяет контексту быть типом значения или неизменяемым.

Если resultSelector не указано, окончательное состояние контекста используется в качестве результата. Это может упростить определение таких функций, как суммирование и подсчет, которые должны увеличивать число на каждой строке и возвращать его.

Укажите resultSelector , чтобы вычислить окончательный результат из контекста после итерации по всем строкам.

Список поддерживаемых типов параметров для аргумента и возвращаемых типов funcсм. в разделе resultSelector".

Если функция детерминирована, укажите isDeterministic , чтобы sqLite использовал дополнительные оптимизации при компиляции запросов.

В следующем примере определяется агрегатная функция для вычисления стандартного отклонения столбца.

connection.CreateAggregate(
    "stdev",

    // A tuple to maintain context between rows
    (Count: 0, Sum: 0.0, SumOfSquares: 0.0),

    // This is called for each row
    ((int Count, double Sum, double SumOfSquares) context, double value) =>
    {
        context.Count++;
        context.Sum += value;
        context.SumOfSquares += value * value;

        return context;
    },

    // This is called to get the final result
    context =>
    {
        var variance = context.SumOfSquares - context.Sum * context.Sum / context.Count;

        return Math.Sqrt(variance / context.Count);
    });

var command = connection.CreateCommand();
command.CommandText =
@"
    SELECT stdev(gpa)
    FROM student
";
var stdDev = command.ExecuteScalar();

Ошибки

Если определяемая пользователем функция вызывает исключение, сообщение возвращается в SQLite. Затем SQLite вызовет ошибку, и Microsoft.Data.Sqlite вызовет sqliteException. Дополнительные сведения см. в разделе об ошибках базы данных.

По умолчанию код ошибки SQLite будет SQLITE_ERROR (или 1). Однако его можно изменить, добавив SqliteException в вашу функцию и указав нужный SqliteErrorCode.

Отладка

SQLite вызывает вашу реализацию напрямую. Это позволяет добавлять точки останова, которые активируются при оценке запросов SQLite. Полный интерфейс отладки .NET доступен для создания пользовательских функций.

См. также