Partager via


Fonctions définies par l’utilisateur

La plupart des bases de données ont un dialecte procédural de SQL que vous pouvez utiliser pour définir vos propres fonctions. SQLite s’exécute toutefois en processus avec votre application. Au lieu d’apprendre un nouveau dialecte sql, vous pouvez simplement utiliser le langage de programmation de votre application.

Fonctions scalaires

Les fonctions scalaires retournent une valeur scalaire unique pour chaque ligne d’une requête. Définissez de nouvelles fonctions scalaires et remplacez les fonctions intégrées à l'aide de CreateFunction.

Consultez les types de données pour obtenir la liste des types de paramètres et de retour pris en charge pour l’argument func .

La spécification de l’argument state passe cette valeur à chaque appel de la fonction. Utilisez cette option pour éviter les fermetures.

Spécifiez isDeterministic si votre fonction est déterministe pour permettre à SQLite d’utiliser des optimisations supplémentaires lors de la compilation de requêtes.

L’exemple suivant montre comment ajouter une fonction scalaire pour calculer le rayon d’un cylindre.

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
";

Opérateurs

Les opérateurs SQLite suivants sont implémentés par les fonctions scalaires correspondantes. La définition de ces fonctions scalaires dans votre application remplace le comportement de ces opérateurs.

Opérateur Fonction
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)

L’exemple suivant montre comment définir la fonction regexp pour activer son opérateur correspondant. SQLite n’inclut pas d’implémentation par défaut de la fonction 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();

Fonctions d’agrégation

Les fonctions d’agrégation retournent une valeur agrégée unique pour toutes les lignes d’une requête. Définissez et remplacez les fonctions agrégées à l'aide de CreateAggregate.

L’argument seed spécifie l’état initial du contexte. Utilisez-le pour éviter également les fermetures.

L’argument func est appelé une fois par ligne. Utilisez le contexte pour parvenir à un résultat final. Renvoyez le contexte. Ce modèle permet au contexte d'être un type de valeur ou immuable.

Si resultSelector n'est pas spécifié, l'état final du contexte est utilisé comme résultat. Cela peut simplifier la définition de fonctions telles que la somme et le nombre qui n’ont besoin que d’incrémenter un nombre par ligne et de le retourner.

Spécifiez resultSelector pour calculer le résultat final à partir du contexte après l’itération de toutes les lignes.

Consultez les types de données pour connaître les types de paramètres pris en charge pour func et les types de retour pour resultSelector.

Si votre fonction est déterministe, spécifiez isDeterministic pour autoriser SQLite à utiliser des optimisations supplémentaires lors de la compilation de requêtes.

L’exemple suivant définit une fonction d’agrégation pour calculer l’écart type d’une colonne.

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();

Erreurs

Si une fonction définie par l’utilisateur lève une exception, le message est retourné à SQLite. SQLite génère ensuite une erreur et Microsoft.Data.Sqlite lève une exception SqliteException. Pour plus d’informations, consultez Erreurs de base de données.

Par défaut, le code d’erreur SQLite est SQLITE_ERROR (ou 1). Vous pouvez toutefois le modifier en générant une exception SqliteException dans votre fonction avec la valeur SqliteErrorCode souhaitée spécifiée.

Débogage

SQLite appelle directement votre implémentation. Cela vous permet d’ajouter des points d’arrêt qui se déclenchent pendant que SQLite évalue les requêtes. L’expérience de débogage .NET complète est disponible pour vous aider à créer vos fonctions définies par l’utilisateur.

Voir aussi