Re: Calcul de médiane

From: Sébastien Dinot <sebastien(dot)dinot(at)free(dot)fr>
To: pgsql-fr-generale(at)postgresql(dot)org
Subject: Re: Calcul de médiane
Date: 2008-06-03 23:10:42
Message-ID: 20080603231042.GB7922@dinot.net
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-fr-generale

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 !

In response to

Browse pgsql-fr-generale by date

  From Date Subject
Next Message Valérie SCHNEIDER 2008-06-04 07:37:36 Re: Problème de select suivant un update
Previous Message Guillaume Lelarge 2008-06-03 21:49:00 Re: Problème de select suivant un update