Article
· Oct 28 2m de lecture

Écriture d'une fonction d'agrégation définie par l'utilisateur dans IRIS - exemple : Median

Les fonctions d'agrégation définies par l'utilisateur sont prises en charge dans IRIS depuis 2021.1.0. J'avais souhaité une étoile pour celle-ci il y a des années avant de trouver un moyen secret et astucieux de remplacer MAX et MIN dans un type de données personnalisé, mais je n'ai pas eu l'occasion d'en essayer un jusqu'à aujourd'hui. J'ai pensé que c'était une expérience/un exemple intéressant - la question de savoir comment obtenir une médiane dans IRIS SQL s'est déjà posée une fois - donc je la partage ici sans trop de commentaires supplémentaires.

Une mise en garde : les UDAF n'ont pas la belle parité objet/SQL que les autres types de fonctions ont, vous devez donc exécuter SQL pour définir la fonction d'agrégation (utilement enveloppée dans une méthode de classe dans l'exemple ci-dessous). La compilation de la classe seule ne suffit pas.

/// Classe implémentant une fonction d'agrégation médiane pour IRIS SQL
Class DC.Demo.Median
{

/// Renvoie une nouvelle référence globale dans IRISTEMP à utiliser pour stocker les résultats intermédiaires
ClassMethod Initialize() As %String [ PublicList = ref, SqlProc ]
{
    New ref
    Set ref = $Name(^IRIS.Temp.UDAF.Median($Increment(^IRIS.Temp.UDAF.Median)))
    Set @ref = 0
    Quit ref
}

/// Met à jour la valeur globale temporaire pour un seul enregistrement
ClassMethod Iterate(ref As %String, value As %Numeric) As %String [ SqlProc ]
{
    If (value '= "") {
        Do $Increment(@ref)
        Do $Increment(@ref@(+value))
    }
    Quit ref
}

/// Trouve la médiane réelle (éventuellement une moyenne des deux valeurs médianes)
ClassMethod Finalize(ref As %String) As %Numeric [ SqlProc ]
{
    Set median = ""
    Set total = @ref
    Set position1 = (total+1)\2
    Set position2 = (total+2)\2
    Set val1 = ""
    Set val2 = ""
    Set reached = 0
    Set key = ""
    For {
        Set key = $Order(@ref@(key),1,refCount)
        Quit:key=""
        set reached = reached + refCount
        if (reached >= position1) && (val1 = "") {
            Set val1 = key
        }
        if (reached >= position2) && (val2 = "") {
            Set val2 = key
        }
        If (val1 '= "") && (val2 '= "") {
            Set median = (val1+val2)/2
            Quit
        }
    }
    Kill @ref
    Quit median
}

/// Pour définir réellement l'UDAF d'un point de vue SQL, appelez cette méthode de classe.
ClassMethod Define()
{
    // Supprimez la fonction au cas où quelque chose aurait changé
    &sql(DROP AGGREGATE DC_Demo.Median)
    &sql(CREATE AGGREGATE DC_Demo.Median(arg NUMERIC) RETURNS NUMERIC
       INITIALIZE WITH DC_Demo.Median_Initialize
       ITERATE WITH DC_Demo.Median_Iterate
       FINALIZE WITH DC_Demo.Median_Finalize)
    $$$ThrowSQLIfError(SQLCODE,%msg)
}

}

J'espère que cela aidera quelqu'un !

Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer