Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SQL Firebird Discussion :

Produit de lignes d'une colonne


Sujet :

SQL Firebird

  1. #1
    Membre habitué
    Produit de lignes d'une colonne
    Bonjour, existe t-il un moyen de faire un produit genre multiplication(col) De la même manière que la fonction sum(col) fait une addition?
    L'idée est que j'ai des taux dans une base, et que je voudrais appliquer plusieurs taux a une donnée.

    Merci d'avance !

  2. #2
    Membre régulier
    Citation Envoyé par nek_kro_kvlt
    Bonjour, existe t-il un moyen de faire un produit genre multiplication(col) De la même manière que la fonction sum(col) fait une addition?
    L'idée est que j'ai des taux dans une base, et que je voudrais appliquer plusieurs taux a une donnée.

    Merci d'avance !
    Voilà une question que je ne m'étais jamais posé. Je ferais ça avec une procédure stockée qui renvoie, au choix, juste le produit de la table des taux ou bien carrément la table complète avec la multiplication déjà réalisée.

  3. #3
    Membre expert
    Il n'y a pas l'équivalent de SUM pour la multiplication
    mais cela doit pouvoir se régler autrement

    un peu de précision sur le problème posé ?
    Philippe Makowski
    IBPhoenix - Firebird
    Membre de l'April

  4. #4
    Membre habitué
    disons que j'ai une table qui contiens différents taux.
    Imagineons que j'ai une table genre

    Nom du taux : valeur
    ---------------------
    12-25ans : 10%
    personnes équipées en téléphone : 25%

    Si je veux avoir les 12-25 ans équipés en téléphone, il faut que je prenne la population * 10 % * 25 % donc population * (10%*25%).

    Je me demandais donc s'il existait un moyen simple de multiplier ces taux entre eux ou s'il fallait que je fasses moi même le calcul...
    C'est assez particulier comme application

  5. #5
    Membre régulier
    Citation Envoyé par nek_kro_kvlt
    disons que j'ai une table qui contiens différents taux.
    Imagineons que j'ai une table genre

    Nom du taux : valeur
    ---------------------
    12-25ans : 10%
    personnes équipées en téléphone : 25%

    Si je veux avoir les 12-25 ans équipés en téléphone, il faut que je prenne la population * 10 % * 25 % donc population * (10%*25%).

    Je me demandais donc s'il existait un moyen simple de multiplier ces taux entre eux ou s'il fallait que je fasses moi même le calcul...
    C'est assez particulier comme application
    Ouf, j'ai une piste ;-) On peut transformer un produit en somme.

    a1*a2*...*an = exp(ln(a1) + ln(a2) + ... + ln(an))

    soit :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    select EXP(SUM(LN(VALEUR))) from LA_TABLE


    Il te reste à trouver une fonction LN (logarithme népérien... pour attendre) et une fonction exponentielle.

    Attention aux débordements, les chiffres deviennent vite très très grands. Ou très très petits.

  6. #6
    Membre régulier
    Citation Envoyé par PierreY
    Il te reste à trouver une fonction LN (logarithme népérien... pour attendre) et une fonction exponentielle.
    Dans IbUDF.dll (ou .so) :

    DECLARE EXTERNAL FUNCTION ln
    DOUBLE PRECISION
    RETURNS DOUBLE PRECISION BY VALUE
    ENTRY_POINT 'IB_UDF_ln' MODULE_NAME 'ib_udf';

    Mais je n'ai pas trouvé d'exponentielle :-(

  7. #7
    Membre expert
    Philippe Makowski
    IBPhoenix - Firebird
    Membre de l'April

  8. #8
    Membre régulier
    Citation Envoyé par makowsky
    C'est un peu moribond ça, non ?

  9. #9
    Membre habitué
    Merci a vous c'est cool

  10. #10
    Membre expert
    Citation Envoyé par PierreY
    C'est un peu moribond ça, non ?
    rfunc, un peu, mais comme il y a les sources, rien n' empêche de prendre un morceau qui serait utile et de le compiler, comme l'exponentiel par exemple.
    Philippe Makowski
    IBPhoenix - Firebird
    Membre de l'April

  11. #11
    Membre expert
    Citation Envoyé par PierreY
    C'est un peu moribond ça, non ?
    Oui hélas, mais ca fonctionne encore bien ^^.

    Et les sources sont disponnibles comme l'a précisé makowski.

    Pour ma part je prendrais l'option de la procédure stoquée afin de me prémunir des problemes d'arrondis que vont engendrer les LN / EXP.

  12. #12
    Membre habitué
    Bah moi j'ai pris RFunc, car la fonction exp n'étais pas dispo dans la version lite de srfunc, mais je vais peut être récrire la fonction exp, vu que je penses développer une UDF en delphi pendant que j'y suis

  13. #13
    Membre régulier
    Citation Envoyé par Barbibulle
    Pour ma part je prendrais l'option de la procédure stoquée afin de me prémunir des problemes d'arrondis que vont engendrer les LN / EXP.
    J'ai cherché deux heures hier soir. Je n'ai pas trouvé de solution qui permette d'exécuter ce genre de requête :

    select mult(taux) from une_table
    where test in ('12-25 ans', 'possède un téléphone portable');

    Le problème c'est qu'il va falloir parser le "IN" depuis un VARCHAR(...) :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    create procedure combine_taux(conditions varchar(32000))
    returns (taux_combine double precision)
    as
      declare variable test varchar(50); /* taille de la colonne "test" de la table */
    begin
      /* head fonctionne comme en lisp, ca renvoie le premier élément et
          ca modifie le paramètre (que l'on a donc passé par référence) en
          enlevant "head"
      */
      taux_combine = 1;
      test = head(conditions);    
      while (test <> '') do
      begin
        select taux_combine * taux from une_table
        where test = :test
        into :taux_combine;
     
        test = head(conditions);
      end
     
      suspend;
    end;


    Si on ne parse pas les conditions dans la procédure stockée, la seule autre solution c'est de prévoir une procédure stockée avec suffisamment de paramètres en entrée pour être utilisable dans tous les cas possibles :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    create procedure combine_taux (
      p1 varchar(50), p2 varchar(50), p3 varchar(50),..., pn varchar(50))
    returns ( taux_combine double precision)
    as
    begin
      select coalesce(t1.taux,1) * coalesce(t2.taux,1) *
               coalesce(t3.taux,1) * .. * coalesce(tn.taux,1)
      from une_table t1, une_table t2, une_table t3, ... , une_table tn
      where t1.test=:p1 and t2.test=:p2 and t3.test=:p3 and ... and tn.test=pn
      into :taux_combine;
     
      suspend;
    end


    Mais j'ai peur que ça ne marche pas, la condition doit être plus subtile que ça, genre il faut utiliser des trucs pour tester quand les paramètres sont nulls ou que les tests n'existent pas.

    Je crois vraiment que la solution du e(sum(ln(taux))) est la plus efficace. Il n'y a pas de raison qu'il y ait plus de problèmes de débordement avec cette solution (il y en aura même certainement moins puisqu'on peut se contenter de la somme des ln qui est < somme des taux et faire l'exponentielle dans l'application avec (ou pas) des librairies de traitement des grands nombres) qu'avec les procédures stockées.

    A moins que tu aies une procédure stockée à base de procédures stockées qui marche avec autant de conditions que nek_kro_kvlt a besoin (car il est là le problème, c'est la selection des taux à combiner entre eux)...

    @+

    --
    Pierre Y.

  14. #14
    Membre habitué
    Sinon, je ne sait pas trop comment marchent les UDF, mais peut être est-il possible d'appeler une UDF qui traiterait un ensemble de ligne, comme si l'on voulait faire une UDF sum, mais je doute que cela soit possible...

    En tous cas merci d'avoir consacré votre temps à mon problème, je vais resté sur la solution ln / e et si j'ai des problèmes je verrai avec les proc stockées, mais normalement il ne devrait pas y avoir de soucis étant donné que la pluspart des taux auront des précision à 10^-2 ou 10^-3

  15. #15
    Membre régulier
    Citation Envoyé par nek_kro_kvlt
    Sinon, je ne sait pas trop comment marchent les UDF, mais peut être est-il possible d'appeler une UDF qui traiterait un ensemble de ligne, comme si l'on voulait faire une UDF sum, mais je doute que cela soit possible...
    Non, une UDF c'est une bête fonction, ca connait les types standards du C : chaines de caractères, nombres, nombres décimaux. Les types structurés (record, enregistrement, ensemble d'enregistrements...) ca ne marche pas, non plus que les objets.

    Citation Envoyé par nek_kro_kvlt
    En tous cas merci d'avoir consacré votre temps à mon problème, je vais resté sur la solution ln / e et si j'ai des problèmes je verrai avec les proc stockées, mais normalement il ne devrait pas y avoir de soucis étant donné que la pluspart des taux auront des précision à 10^-2 ou 10^-3
    Ca marchera, j'ai testé dans la calculette ;-)

  16. #16
    Membre habitué
    Citation Envoyé par PierreY Voir le message
    Ouf, j'ai une piste ;-) On peut transformer un produit en somme.

    a1*a2*...*an = exp(ln(a1) + ln(a2) + ... + ln(an))

    soit :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    select EXP(SUM(LN(VALEUR))) from LA_TABLE


    Il te reste à trouver une fonction LN (logarithme népérien... pour attendre) et une fonction exponentielle.

    Attention aux débordements, les chiffres deviennent vite très très grands. Ou très très petits.
    Exactement, ça peut donner sur SQL Server l'erreur :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    Msg 3623, Level 16, State 1, Line 43
    Une opération en virgule flottante non valide s'est produite.


    que j’essaie toujours de résoudre