用户定义的函数

大多数数据库都具有 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 GLOB Y glob(Y, X)
X LIKE Y like(Y, X)
X LIKE Y ESCAPE Z like(Y, X, Z)
X MATCH 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 调试体验可帮助你创建用户定义函数。

请参阅