Funciones definidas por el usuario
La mayoría de las bases de datos tienen un dialecto de procedimientos de SQL que puede usar para definir sus propias funciones. SQLite, en cambio, se ejecuta en el mismo proceso que la aplicación. Así, en lugar de tener que aprender un nuevo dialecto de SQL, se puede usar simplemente el lenguaje de programación de la aplicación en cuestión.
Funciones escalares
Las funciones escalares devuelven un único valor escalar por cada fila de una consulta. Use CreateFunction para definir nuevas funciones escalares e invalidar las que estén integradas.
Vea Tipos de datos para obtener una lista de los tipos de parámetro y de valor devuelto admitidos en el argumento func
.
Si se especifica el argumento state
, ese valor se pasará a cada invocación de la función. Recurra a este método para evitar cierres.
Si la función es determinista, especifique isDeterministic
para permitir que SQLite use más optimizaciones al compilar consultas.
En el siguiente ejemplo se muestra cómo agregar una función escalar para calcular el radio de un cilindro.
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
";
Operadores
Los siguientes operadores de SQLite se implementan a través de las funciones escalares correspondientes. Al definir estas funciones escalares en la aplicación, el comportamiento de estos operadores se invalidará.
Operador | Función |
---|---|
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) |
En el siguiente ejemplo se muestra cómo definir la función RegExp para habilitar su operador correspondiente. SQLite no incluye una implementación predeterminada de la función 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();
Funciones de agregado
Las funciones de agregado devuelven un único valor agregado para todas las filas de una consulta. Use CreateAggregate para definir e invalidar funciones de agregado.
El argumento seed
especifica el estado inicial del contexto. Recurra a este método también para evitar cierres.
El argumento func
se invoca una vez por cada fila. Use el contexto para acumular un resultado final. Devuelva el contexto. Este patrón permite que el contexto sea un tipo de valor o inmutable.
Si no se especifica ningún elemento resultSelector
, se usa como resultado el estado final del contexto. Esto puede simplificar la definición de funciones como SUM y COUNT, donde solo es necesario aumentar un número cada fila y devolver el valor correspondiente.
Especifique resultSelector
para calcular el resultado final del contexto después de recorrer en iteración todas las filas.
Vea Tipos de datos para obtener una lista de los tipos de parámetro del argumento func
y los tipos devueltos de resultSelector
.
Si la función es determinista, especifique isDeterministic
para permitir que SQLite use más optimizaciones al compilar consultas.
En el siguiente ejemplo se define una función de agregado para calcular la desviación estándar de una columna.
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();
Errores
Si una función definida por el usuario produce una excepción, el mensaje se devuelve a SQLite. Tras ello, SQLite producirá un error y Microsoft.Data.Sqlite producirá una excepción SqliteException. Para más información, vea Errores de base de datos.
El código de error del error de SQLite será de forma predeterminada SQLITE_ERROR (o 1), pero se puede cambiar produciendo una excepción SqliteException en la función con el elemento SqliteErrorCode deseado especificado.
Depuración
SQLite llama directamente a su implementación, lo que le permite agregar puntos de interrupción que se desencadenan mientras SQLite está evaluando consultas. La experiencia de depuración completa de .NET está disponible para ayudarle a crear funciones definidas por el usuario.