Re: Calcul de médiane

Lists: pgsql-fr-generale
From: Sébastien DINOT <sebastien(dot)dinot(at)free(dot)fr>
To: pgsql-fr-generale(at)postgresql(dot)org
Subject: Calcul de médiane
Date: 2007-02-21 10:12:13
Message-ID: 1172052733.45dc1afd99d1f@imp.free.fr
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

Bonjour à tous,

Je souhaite calculer la médiane d'un ensemble de valeurs et je ne vois
pas comment le faire simplement. Une âme charitable aurait-elle une
solution à me proposer ?

Pour mémoire, la médiane est différente de la moyenne :

http://fr.wikipedia.org/wiki/M%C3%A9diane_(centre) :

----------------------------------------------------------------------
Médiane (centre)

En théorie des probabilités et en statistiques, la médiane est un nombre
qui divise en deux parties l'échantillon, la population ou la
distribution de probabilités. Chaque partie contient le même nombre de
valeurs.

Dans une liste finie de valeurs, il suffit d'ordonner les valeurs dans
un ordre croissant et de choisir la valeur au milieu comme médiane. S'il
y a un nombre pair de valeurs, la moyenne arithmétique est souvent
prise.

Contrairement à la moyenne arithmétique, la valeur médiane permet
d'atténuer l'influence perturbatrice des valeurs extrêmes enregistrées
lors de circonstances exceptionnelles.

[...]

Médianes en statistiques descriptives

La médiane est principalement utilisée pour les distributions
asymétriques, car elle les représente mieux que la moyenne arithmétique.
Considérons l'ensemble { 1, 2, 2, 2, 3, 9 }. La médiane est 2, tout
comme le mode, ce qui est une meilleure mesure de tendance centrale que
la moyenne arithmétique de 3.166….

Le calcul de la médiane est couramment effectué pour représenter
différentes distributions et elle est facile à comprendre, tout comme à
calculer. Elle est aussi plus robuste que la moyenne en présence de
valeurs extrêmes.

----------------------------------------------------------------------

Par exemple, voici une distribution de 200 valeurs :

Valeur | Occurrences
--------+-------------
0.00 | 5
10.00 | 45
12.00 | 1
20.00 | 75
25.00 | 19
30.00 | 25
50.00 | 29
480.00 | 1

La moyenne est de 25.585.

La médiane est de 20 (100 valeurs sont <= 20 et 100 valeurs sont >= 20).

On m'a déjà signalé une solution en PL/R :

http://www.joeconway.com/plr/doc/plr-aggregate-funcs.html

mais je préfèrerais passer par une requête SQL ou une procédure stockée
en PL/PgSQL.

Je vous remercie par avance,

Sébastien

--
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 !


From: Stephane Bortzmeyer <bortzmeyer(at)nic(dot)fr>
To: Sébastien DINOT <sebastien(dot)dinot(at)free(dot)fr>
Cc: pgsql-fr-generale(at)postgresql(dot)org
Subject: Re: Calcul de médiane
Date: 2007-02-21 11:22:58
Message-ID: 20070221112258.GA25559@nic.fr
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

On Wed, Feb 21, 2007 at 11:12:13AM +0100,
Sébastien DINOT <sebastien(dot)dinot(at)free(dot)fr> wrote
a message of 79 lines which said:

> Pour mémoire, la médiane est différente de la moyenne :

Oui, et, dans 90 % de cas où on utilise la moyenne, on devrait
utiliser la médiane à la place.

http://www.bortzmeyer.org/mediane-et-moyenne.html

Si on met vos données ainsi :

CREATE TABLE Data (
valeur FLOAT,
occurrences INTEGER);

INSERT INTO Data (valeur, occurrences) VALUES (0, 5);
INSERT INTO Data (valeur, occurrences) VALUES (10, 45);
INSERT INTO Data (valeur, occurrences) VALUES (12, 1);
INSERT INTO Data (valeur, occurrences) VALUES (20, 75);
INSERT INTO Data (valeur, occurrences) VALUES (25, 19);
INSERT INTO Data (valeur, occurrences) VALUES (30, 25);
INSERT INTO Data (valeur, occurrences) VALUES (480, 1);
INSERT INTO Data (valeur, occurrences) VALUES (50, 29);

Et que, pour aider, on crée les fonctions auxiliaires suivantes :

CREATE OR REPLACE FUNCTION occurrences_cumulees(FLOAT) RETURNS INTEGER AS
'SELECT sum(occurrences)::INTEGER FROM Data WHERE Valeur <= $1;'
LANGUAGE SQL;

CREATE OR REPLACE FUNCTION Moitie_population() RETURNS INTEGER AS
'SELECT sum(occurrences)::INTEGER/2 FROM Data;'
LANGUAGE SQL;

La médiane peut alors se calculer facilement :

SELECT min(valeur) AS median FROM Data
WHERE occurrences_cumulees(valeur) >= Moitie_population();

Testons :

essais=> SELECT valeur, occurrences, occurrences_cumulees(valeur) FROM Data ORDER BY valeur;
valeur | occurrences | occurrences_cumulees
--------+-------------+----------------------
0 | 5 | 5
10 | 45 | 50
12 | 1 | 51
20 | 75 | 126
25 | 19 | 145
30 | 25 | 170
50 | 29 | 199
480 | 1 | 200
(8 rows)

essais=> SELECT min(valeur) AS median FROM Data
essais-> WHERE occurrences_cumulees(valeur) >= Moitie_population();
median
--------
20
(1 row)


From: Stephane Bortzmeyer <bortzmeyer(at)nic(dot)fr>
To: Sébastien DINOT <sebastien(dot)dinot(at)free(dot)fr>
Cc: pgsql-fr-generale(at)postgresql(dot)org
Subject: Re: Calcul de médiane
Date: 2007-02-21 12:59:30
Message-ID: 20070221125930.GA4482@nic.fr
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

On Wed, Feb 21, 2007 at 12:22:58PM +0100,
Stephane Bortzmeyer <bortzmeyer(at)nic(dot)fr> wrote
a message of 65 lines which said:

> SELECT min(valeur) AS median FROM Data
> WHERE occurrences_cumulees(valeur) >= Moitie_population();

Après, je laisse les lecteurs déboguer les cas rigolos comme celui où
aucune occurrence n'est pile sur la médiane, etc.


From: Emmanuel Seyman <emmanuel(dot)seyman(at)club-internet(dot)fr>
To: pgsql-fr-generale(at)postgresql(dot)org
Subject: Re: Calcul de médiane
Date: 2007-02-21 13:05:32
Message-ID: 20070221130532.GA6346@orient.maison.lan
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

* Stephane Bortzmeyer [21/02/2007 14:01]:
>
> Après, je laisse les lecteurs déboguer les cas rigolos comme celui où
> aucune occurrence n'est pile sur la médiane, etc.

En fait, si on a un nombre pair d'éléments, il faut faire la moyenne
entre les deux élements en milieu de tableau.

Emmanuel


From: Stephane Bortzmeyer <bortzmeyer(at)nic(dot)fr>
To: pgsql-fr-generale(at)postgresql(dot)org
Subject: Re: Calcul de médiane
Date: 2007-02-21 13:34:33
Message-ID: 20070221133433.GA9297@nic.fr
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

On Wed, Feb 21, 2007 at 02:05:32PM +0100,
Emmanuel Seyman <emmanuel(dot)seyman(at)club-internet(dot)fr> wrote
a message of 12 lines which said:

> En fait, si on a un nombre pair d'éléments,

Avec le schéma de données choisi par l'OP (valeur unique, nombre
d'occurrences), c'est plus compliqué que ça. Je n'ai pas voulu changer
son schéma de données, sinon cette solution aurait sans doute marché :

http://book.itzero.com/read/others/0602/OReilly.SQL.Cookbook.Dec.2005_html/0596009763/sqlckbk-CHP-7-SECT-10.html


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: 2007-02-21 14:01:27
Message-ID: 1172066487.45dc50b72c183@imp.free.fr
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

En premier lieu, je remercie Emmanuel et Stéphane pour leurs réponses.

Ensuite, la forme sous laquelle j'ai présenté les données avait pour
seul but de raccourcir mon mail. Dans les faits, j'ai bien en base une
série de 200 valeurs.

Selon Stephane Bortzmeyer <bortzmeyer(at)nic(dot)fr>:
| Avec le schéma de données choisi par l'OP (valeur unique, nombre
| d'occurrences), c'est plus compliqué que ça. Je n'ai pas voulu
| changer son schéma de données, sinon cette solution aurait sans
| doute marché :
|
http://book.itzero.com/read/others/0602/OReilly.SQL.Cookbook.Dec.2005_html/0596009763/sqlckbk-CHP-7-SECT-10.html

Merci pour le lien, je vais l'étudier.

A++, Sébastien

--
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 !


From: Stéphane BUNEL <stephane(at)stratum-ip(dot)net>
To: pgsql-fr-generale(at)postgresql(dot)org
Subject: Re: Calcul de médiane
Date: 2007-02-21 15:52:51
Message-ID: 45DC6AD3.6040907@stratum-ip.net
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

Stephane Bortzmeyer wrote:
> On Wed, Feb 21, 2007 at 11:12:13AM +0100,
> Sébastien DINOT <sebastien(dot)dinot(at)free(dot)fr> wrote
> a message of 79 lines which said:
>
>> Pour mémoire, la médiane est différente de la moyenne :
>
> Oui, et, dans 90 % de cas où on utilise la moyenne, on devrait
> utiliser la médiane à la place.

Le problème n'est-il pas aussi que, trop souvent, la moyenne est
présentée sans son inséparable compagnon, l'écart type ?

De fait il est difficile, au premier coup d'oeil, d'estimer la
pertinence de la donnée. Technique sophiste. En ces temps électoraux je
me garderais bien de faire un parallèle :-)

Stéphane BUNEL.


From: Stephane Bortzmeyer <bortzmeyer(at)nic(dot)fr>
To: Stéphane BUNEL <stephane(at)stratum-ip(dot)net>
Cc: pgsql-fr-generale(at)postgresql(dot)org
Subject: Re: Calcul de médiane
Date: 2007-02-21 16:27:13
Message-ID: 20070221162713.GA537@nic.fr
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

On Wed, Feb 21, 2007 at 04:52:51PM +0100,
Stéphane BUNEL <stephane(at)stratum-ip(dot)net> wrote
a message of 25 lines which said:

> >Oui, et, dans 90 % de cas où on utilise la moyenne, on devrait
> >utiliser la médiane à la place.
>
> Le problème n'est-il pas aussi que, trop souvent, la moyenne est
> présentée sans son inséparable compagnon, l'écart type ?

Oui, c'est vrai mais le couple (moyenne, écart-type) est difficile à
analyser. Il me semble que le concept de médiane est plus simple.

> De fait il est difficile, au premier coup d'oeil, d'estimer la
> pertinence de la donnée. Technique sophiste. En ces temps électoraux
> je me garderais bien de faire un parallèle :-)

C'est clair qu'indiquer le salaire moyen est plus optimiste que
d'indiquer le salaire médian (le premier est sérieusement tiré vers le
haut par quelques gros salaires).


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: 2007-02-21 22:46:29
Message-ID: 20070221224629.GA5900@achille.maison
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

Stephane Bortzmeyer a écrit :
| Avec le schéma de données choisi par l'OP (valeur unique, nombre
| d'occurrences), c'est plus compliqué que ça. Je n'ai pas voulu changer
| son schéma de données, sinon cette solution aurait sans doute marché :
|
| http://book.itzero.com/read/others/0602/OReilly.SQL.Cookbook.Dec.2005_html/0596009763/sqlckbk-CHP-7-SECT-10.html

Finalement, la méthode proposée semble fonctionner mais elle a deux
défauts à mon goût :

- quitte à passer pour le simplet de service, j'avoue que je l'ai
reproduite sans la comprendre ;

- elle est terriblement lente (logique vu l'auto-jointure qui se fait
sans critère dans mon cas et porte donc sur l'intégralité de la
table).

Je m'en suis finalement sorti en écrivant une procédure stockée en
PL/PgSQL qui :

- compte le nombre de valeurs => nbv;

- ouvre un curseur sur la liste triée des valeurs, à partir de la
moitié (offset nbv / 2) et m'extrait 2 valeurs (limit 2) => v1, v2.

- renvoie :

- lorsque nbv % 2 vaut 0 (i.e nombre pair de valeurs) : (v1 + v2) / 2.0

- lorsque nbv % 2 vaut 1 (i.e nombre impair de valeurs) : v1

Je vous remercie pour votre aide.

A++, Sébastien

--
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 !


From: Dimitri Fontaine <dim(at)dalibo(dot)com>
To: pgsql-fr-generale(at)postgresql(dot)org
Subject: Re: Calcul de médiane
Date: 2007-02-21 23:56:54
Message-ID: 200702220056.54378.dim@dalibo.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

Bonjour à tous,

Le mercredi 21 février 2007 23:46, Sébastien Dinot a écrit :
> - quitte à passer pour le simplet de service

Même exercice :)

> - lorsque nbv % 2 vaut 0 (i.e nombre pair de valeurs) : (v1 + v2) / 2.0

Il me semblait pourtant que la médiane devait être une valeur présente dans le
jeu de données... comment être sûr de cela avec ton implémentation ?

--
Dimitri Fontaine


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: 2007-02-22 00:15:45
Message-ID: 20070222001545.GA6744@achille.maison
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

Salut Dim,

Dimitri Fontaine a écrit :
| > - lorsque nbv % 2 vaut 0 (i.e nombre pair de valeurs) : (v1 + v2) / 2.0
|
| Il me semblait pourtant que la médiane devait être une valeur
| présente dans le jeu de données...

Je n'ai pas connaissance d'une telle contrainte. D'ailleurs, si tu as
l'ensemble :

1, 3, 5, 11, 19

La médiane est bien 5

Mais si tu n'as que l'ensemble :

1, 3, 11, 19

Aucune de ces valeurs ne sauraient être la médiane selon la définition
fournie dans Wikimedia :

http://fr.wikipedia.org/wiki/M%C3%A9diane_%28centre%29 :

« En théorie des probabilités et en statistiques, la médiane est un
nombre qui divise en deux parties l'échantillon, la population ou la
distribution de probabilités. Chaque partie contient le même nombre
de valeurs. »

Par contre, toutes les valeurs entières (pour ne rester que dans cet
ensemble) de l'intervalle [ 4 ; 10 ] font des médianes convenables.

Dès lors, le plus simple est de prendre la moyenne des valeurs
immédiatement inférieure et supérieure, ici : ( 3 + 11 ) / 2 = 7. Mon
algo considèrera donc 7 comme la valeur médiane.

A++, Sébastien

--
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 !


From: Dimitri Fontaine <dim(at)dalibo(dot)com>
To: pgsql-fr-generale(at)postgresql(dot)org
Subject: Re: Calcul de médiane
Date: 2007-02-22 00:44:44
Message-ID: 200702220144.44900.dim@dalibo.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

Bonsoir Sébastien,

Le jeudi 22 février 2007 01:15, Sébastien Dinot a écrit :
> | Il me semblait pourtant que la médiane devait être une valeur
> | présente dans le jeu de données...
>
> Je n'ai pas connaissance d'une telle contrainte.

Je me souvenais avoir appris cela, et en suivant les liens de la page
wikipédia indiquée, je suis tombé là-dessus :

http://www.statcan.ca/francais/edu/power/ch11/median/median_f.htm

« Techniquement, la médiane doit correspondre à une variable possible.
Dans l'exemple ci-dessus, les variables sont discrètes et sont toujours des
nombres entiers. Par conséquent, 7,5 n'est pas une variable possible,
puisque personne ne peut frapper 7,5 coups de circuit. Ce nombre a une
signification, mais seulement dans un contexte statistique. Certains
mathématiciens pourraient faire valoir que 8 est une médiane plus
appropriée. »

Ce qui donne plus de souplesse que ne m'en offrait mon prof de math, au moins
dans mes souvenirs :)

> Mais si tu n'as que l'ensemble :
> 1, 3, 11, 19
[...]
> Dès lors, le plus simple est de prendre la moyenne des valeurs
> immédiatement inférieure et supérieure, ici : ( 3 + 11 ) / 2 = 7. Mon
> algo considèrera donc 7 comme la valeur médiane.

On dirait que ça dépend surtout de l'usage que tu comptes faire de cette
médiane...
Et la lecture rapide des pages indiquées ici ne me permet pas de savoir
choisir pour médiane un des éléments de l'ensemble {1, 3, 11, 19}.

Bonne continuation,
--
Dimitri Fontaine


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: 2007-02-22 12:05:16
Message-ID: 1172145916.45dd86fcdec09@imp.free.fr
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

Selon Dimitri Fontaine <dim(at)dalibo(dot)com>:
| Je me souvenais avoir appris cela

D'autres personnes - mais pas toutes - m'ont dit la même chose que toi.

En fait, cela dépend de l'approche du problème. Selon qu'elle est
ensembliste ou statistique, on cherchera ou non à rapprocher la médiane
d'une valeur appartenant à l'échantillon étudié.

Pour te montrer que les deux visions s'affrontent sur le web, voici une
autre page que je viens de trouver :

http://www.bibmath.net/dico/index.php3?action=affiche&quoi=./m/mediane.html

sur laquelle on peut lire :

« On appelle médiane d'une série statistique toute valeur M qui partage
le groupe étudié en deux sous-groupes de même effectif, chacun tel que :

* tous les éléments du premier groupe ont des valeurs inférieures ou
égales à M.
* tous les éléments du deuxième groupe ont des valeurs supérieures
ou égales à M.

Avec cette définition, une médiane est rarement unique : par exemple,
si on a 4 notes, 10,12,14,16, alors toute valeur comprise entre 12 et 14
est une médiane possible. On détermine souvent une médiane en prenant
l'intersection des courbes à effectif cumulé (une à effectifs cumulés
croissants, l'autre à effectifs cumulés décroissants). »

Dans mon cas, le but étant de calculer la médiane de cotisations pour
effectuer un budget prévisionnel, l'approche statistique est tout à fait
pertinente.

A++, Sébastien

--
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 !


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: 2007-02-22 12:10:56
Message-ID: 1172146256.45dd88503d57d@imp.free.fr
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

Selon Sébastien DINOT <sebastien(dot)dinot(at)free(dot)fr>:
| En fait, cela dépend de l'approche du problème. Selon qu'elle est
| ensembliste ou statistique, on cherchera ou non à rapprocher la
| médiane d'une valeur appartenant à l'échantillon étudié.

D'ailleurs, cette remarque vaut tout autant pour la moyenne.

Sébastien

--
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 !


From: Stephane Bortzmeyer <bortzmeyer(at)nic(dot)fr>
To: Stéphane BUNEL <stephane(at)stratum-ip(dot)net>
Cc: pgsql-fr-generale(at)postgresql(dot)org
Subject: Re: Calcul de médiane
Date: 2007-03-07 21:21:15
Message-ID: 20070307212115.GA15120@sources.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-fr-generale

On Wed, Feb 21, 2007 at 04:52:51PM +0100,
Stéphane BUNEL <stephane(at)stratum-ip(dot)net> wrote
a message of 25 lines which said:

> Le problème n'est-il pas aussi que, trop souvent, la moyenne est
> présentée sans son inséparable compagnon, l'écart type ?

Ah, au fait, une excellente source :

http://www.statsoft.com/textbook/stbasic.html

Excellent texte de statistiques expliquées aux ingénieurs
non-mathématiciens.

Une autre méthode pour rendre la moyenne supportable (éliminer les
points qui dévient trop) est expliquée là :

http://www.statsoft.com/textbook/stbasic.html#Correlationse


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
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 !