Skip site navigation (1) Skip section navigation (2)

Peripheral Links

Header And Logo

PostgreSQL
| The world's most advanced open source database.

Site Navigation

Search archives
  Advanced Search

Re: Ca lcul de médiane


  • From: Sébastien Dinot <sebastien(dot)dinot(at)free(dot)fr>
  • To: pgsql-fr-generale(at)postgresql(dot)org
  • Subject: Re: Ca lcul de médiane
  • Date: Wed, 4 Jun 2008 01:10:42 +0200
  • Message-id: <20080603231042.GB7922@dinot.net> <text/plain>

Bonjour,

En février 2007, j'avais demandé ici même s'il existait une méthode
prête à l'emploi pour calculer la médiane d'un ensemble de valeurs :

http://archives.postgresql.org/pgsql-fr-generale/2007-02/msg00009.php

J'avais fini par écrire une procédure stockée et à en expliquer les
grandes lignes sur la liste :

http://archives.postgresql.org/pgsql-fr-generale/2007-02/msg00018.php

Sur le coup, j'ai sérieusement manqué de jugeotte en négligeant de
joindre le code à l'explication. Or, comme mon message initial est le
premier lien renvoyé par Google lorsqu'on recherche les mots clés
« PostgreSQL médiane », plusieurs personnes m'ont depuis demandé si je
pouvais leur fournir le code de ma procédure. Il semble donc pertinent
de poster ledit code ici, même avec 16 mois de retard. Avant que l'un
d'entre vous ne s'exclame « Et la licence !? », je précise tout de
suite que toute personne intéressée par ce modeste code peut
l'utiliser et l'adapter comme bon lui semble.

Si d'autres ont des critiques ou des améliorations en tête, qu'ils
n'hésitent pas un instant à en faire profiter tout le monde.

A++, Sébastien

----------------------------------------------------------------------
CREATE FUNCTION mediane_cotisation (VARCHAR, DATE) RETURNS NUMERIC(10,2) AS
'
  DECLARE
    val_type    ALIAS FOR $1; -- Type d'adhesion
    val_date    ALIAS FOR $2; -- Date a laquelle se rapporte la mediane
    nb_adh      INT;
    montant_inf NUMERIC(10,2);
    montant_sup NUMERIC(10,2);
    val_med     NUMERIC(10,2);

    curseur CURSOR (moitie INT) FOR
            SELECT SUM(c.montant)
              FROM cotisation AS c
              JOIN adhesion AS a ON c.id_adhesion = a.id_adhesion
             WHERE c.date_effet <= val_date
               AND c.date_echeance >= val_date
               AND a.type_adhesion = val_type
          GROUP BY c.id_adhesion
          ORDER BY SUM(c.montant)
            OFFSET moitie
             LIMIT 2;

  BEGIN
    nb_adh := ( SELECT COUNT(DISTINCT c.id_adhesion)
                FROM cotisation AS c
                JOIN adhesion AS a ON c.id_adhesion = a.id_adhesion
               WHERE c.date_effet <= val_date
                 AND c.date_echeance >= val_date
                 AND a.type_adhesion = val_type );

    IF nb_adh % 2 = 0 THEN
      OPEN curseur((nb_adh / 2) - 1);
      FETCH curseur INTO montant_inf;
      FETCH curseur INTO montant_sup;
      CLOSE curseur;
      val_med := (montant_inf + montant_sup) / 2.0;
    ELSE
      OPEN curseur(nb_adh / 2);
      FETCH curseur INTO montant_inf;
      CLOSE curseur;
      val_med := montant_inf;
    END IF;


    RETURN val_med;
  END;
' LANGUAGE 'plpgsql';
----------------------------------------------------------------------



-- 
Sébastien Dinot, sebastien(dot)dinot(at)free(dot)fr
http://sebastien.dinot.free.fr/
Ne goûtez pas au logiciel libre, vous ne pourriez plus vous en passer !



Home | Main Index | Thread Index

Privacy Policy | About PostgreSQL
Copyright © 1996 – 2012 PostgreSQL Global Development Group