IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
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

Requêtes PostgreSQL Discussion :

Fonction d'agrégat "produit"


Sujet :

Requêtes PostgreSQL

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 3
    Points : 2
    Points
    2
    Par défaut Fonction d'agrégat "produit"
    Bonjour,

    Existe-t-il dans postgresql une fonction d'agrégat permettant de faire un produit des valeurs d'un champ dans une table, un peu de la même manière que Sum permet de faire une somme?

    Une fonction du genre: "select prod(champ_nb) from T group by champ_x"

    avec comme résultat le produit des valeurs de champ_nb. Exemple
    Code :

    champ_x | champ_nb
    A 2
    A 5
    A 4
    A 3
    B 2
    B 6
    B 2

    Résultat:
    A 120 (2*5*4*3)
    B 24 (2*6*2)

    Une solution est possible en passant par l'exponentielle de la somme des logarithmes des enregistrements "exp(sum(ln(x)))". Mais cette opération n'est pas vraiment satisfaisante dans les cas ou certains enregistrements ont une valeur nulle et renvoie donc systématiquement une erreur.

    Bien cordialement.

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    1 874
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 874
    Points : 2 890
    Points
    2 890
    Par défaut
    Si ça n'existe pas, on peut créer assez facilement une fonction d'aggrégat, par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    CREATE AGGREGATE mmul(int4)
    (
      sfunc = int4mul,
      stype = int4
    );
    Ici la fonction mmul prend des entiers et renvoie le produit de tous ses arguments.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    select mmul(a) from generate_series(1,5) as a;
     mmul 
    ------
      120
    (1 row)

  3. #3
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 571
    Points
    52 571
    Billets dans le blog
    5
    Par défaut
    encore plus simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    CREATE TABLE T (champ_x CHAR(1), champ_nb DECIMAL(16, 2));
     
    INSERT INTO T VALUES ('A', 2);
    INSERT INTO T VALUES ('A', 5);
    INSERT INTO T VALUES ('A', 4);
    INSERT INTO T VALUES ('A', 3);
    INSERT INTO T VALUES ('B', 2);
    INSERT INTO T VALUES ('B', 6);
    INSERT INTO T VALUES ('B', 2);
    Solution :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT champ_x, CAST(EXP(SUM(LN(champ_nb))) AS INT) AS MULT
    FROM T
    GROUP BY champ_x
    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  4. #4
    Candidat au Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 3
    Points : 2
    Points
    2
    Par défaut
    Bonjour,

    Merci pour toutes vos réponses, créer directement une fonction d'agrégat me semble plus adapté à mes besoins.
    Existe t'il une fonction équivalente à 'int4mul' permettant de calculer le produit de nombres réels plutôt que des entiers?

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 3
    Points : 2
    Points
    2
    Par défaut
    Ça y est j'ai la solution à mon problème !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    CREATE AGGREGATE nmul(numeric)
    (
      sfunc = numeric_mul,
      stype = numeric
    );
    Merci encore pour les conseils.


    Cordialement

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    1 874
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 874
    Points : 2 890
    Points
    2 890
    Par défaut
    Pour trouver les différentes fonctions associées à l'opérateur de multiplication '*', il faut faire une requête de ce style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    select oprcode,t1.typname as gauche, t2.typname as droite, t3.typname as resultat
     from pg_catalog.pg_operator join pg_catalog.pg_type t1 on oprleft=t1.oid
     join pg_catalog.pg_type t2 on t2.oid=oprright
     join pg_catalog.pg_type t3 on t3.oid=oprresult
     where oprname='*'
    En 8.3 ça sort ce résultat:
    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
    23
    24
    25
    26
    27
    28
    29
     
        oprcode     |  gauche  |  droite  | resultat 
    ----------------+----------+----------+----------
     int4mul        | int4     | int4     | int4
     int2mul        | int2     | int2     | int2
     int24mul       | int2     | int4     | int4
     int42mul       | int4     | int2     | int4
     float4mul      | float4   | float4   | float4
     float8mul      | float8   | float8   | float8
     int8mul        | int8     | int8     | int8
     int84mul       | int8     | int4     | int8
     int48mul       | int4     | int8     | int8
     point_mul      | point    | point    | point
     path_mul_pt    | path     | point    | path
     box_mul        | box      | point    | box
     cash_mul_flt4  | money    | float4   | money
     flt4_mul_cash  | float4   | money    | money
     cash_mul_flt8  | money    | float8   | money
     cash_mul_int4  | money    | int4     | money
     cash_mul_int2  | money    | int2     | money
     flt8_mul_cash  | float8   | money    | money
     int4_mul_cash  | int4     | money    | money
     int2_mul_cash  | int2     | money    | money
     float48mul     | float4   | float8   | float8
     float84mul     | float8   | float4   | float8
     circle_mul_pt  | circle   | point    | circle
     interval_mul   | interval | float8   | interval
     mul_d_interval | float8   | interval | interval
     numeric_mul    | numeric  | numeric  | numeric

+ Répondre à la discussion
Cette discussion est résolue.

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo