Moyenne discriminante dans une bdd

Petit nouveau ! | 2 Messages

29 oct. 2010, 16:21

Bonjour à tous,

Je n'ai pas trouvé la solution à mon problème dans l'historique du forum, mon problème n'est pas évident à formuler alors je vais le simplifier, le voici:

Imaginons que ma base de données contiennent (schématiquement) ces informations:

1 5 6
3 0 3
4 1 0

Donc 3 lignes et 3 colonnes, ou plutôt 3 entrées ayant chacune 3 caractéristiques (désolé je ne connais pas le vocabulaire précis). Je cherche la requête mysql qui me permettra d'obtenir la moyenne de tout ça MAIS sans prendre en compte les "0", ce qui devra me donner: (1 + 5 + 6 + 3 + 3 + 4 + 1) / 7 et non (1 + 5 +6 + 3 + 0 + 3 + 4 + 1 + 0) / 9.

J'ai vraiment du mal avec ce truc et je commence à avoir mal à la tête!


Quelqu'un peut m'aider? Merci d'avance
Cynth'

Mammouth du PHP | 19672 Messages

29 oct. 2010, 18:30

Intéressant problème, j'ai un peu patiné dessus, mais je suis arrivé au résultat voulu en utilisant une sous-requête UNION :
SELECT
    (SUM(tg.sum_col)/SUM(tg.nb_lignes)) AS moyenne_globale 
FROM (
    SELECT 
        SUM(t1.c1) AS sum_col,
        COUNT(t1.c1) as nb_lignes
    FROM `test` t1
    WHERE t1.c1 > 0
    UNION
    SELECT 
        SUM(t2.c2) AS sum_col,
        COUNT(t2.c2) as nb_lignes
    FROM `test` t2
    WHERE t2.c2 > 0
    UNION
    SELECT 
        SUM(t3.c3) AS sum_col,
        COUNT(t3.c3) as nb_lignes
    FROM `test` t3
    WHERE t3.c3 > 0
) AS tg;
Sommairement, dans la sous-requête, je fais le total de la colonne et je compte le nombre de ligne dont la valeur est supérieure à 0; Il ne me reste qu'à faire la fraction du total des sommes de collones par le total des nombres de lignes :) Un détail, attention aux alias, chaque occurrence de requête dans la sous-requête UNION doit utiliser des alias de table différents.

Enjoy! :pouce:
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Petit nouveau ! | 2 Messages

29 oct. 2010, 20:49

T'es super Cyrano! Je vais me pencher illico-presto là-dessus, y a des choses nouvelles pour moi mais ça m'a l'air accessible.

Merci beaucoup.
Cynth'

Mammouth du PHP | 19672 Messages

30 oct. 2010, 00:48

En fait le seul truc qui est relativement hors normes par rapport au SELECT le plus courant, c'est la sous-requête UNION. En fait j'ai préféré passer par là plutôt que de tenter une unique sous-requête avec des problèmes de GROUP BY, donc la sous-requête est composée de requêtes pour chacune des colonnes à traiter, une par colonne donc ici trois. Chacune fait le total des valeurs de la colonne sans discrimination particulière puisqu'en additionnant un nombre à zéro ne changera rien, en revanche le nombre de ligne ne doit comporter que les lignes ayant une valeur supérieure à zéro, d'où la clause WHERE : j'ai donc deux valeurs permettant de faire une moyenne. On ajoute un alias pour les colonnes de résultat qui doivent être les mêmes dans mes trois requêtes.

L'étape suivante est donc une requête sur une requête, la seconde avec UNION créant, en quelque sorte, une table virtuelle que je peux utiliser comme une table conventionnelle.

Si certains détails te semblent encore un peu flou, demande des précisions :)
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

ViPHP
ViPHP | 2291 Messages

30 oct. 2010, 16:38

Salut,

Moi j'aurais fait comme ceci :
SELECT SUM(c1 + c2 + c3) /
 (SUM(IF(c1 != 0, 1, 0) ) +
  SUM(IF(c2 != 0, 1, 0) ) +
  SUM(IF(c3 != 0, 1, 0) ) ) AS RESULT FROM t1 
Mais j'ai peut-être pas capter :)
ImageCe que l'on apprend par l'effort reste toujours ancré beaucoup plus longtemps.

Mammouth du PHP | 19672 Messages

30 oct. 2010, 16:47

Salut,

Moi j'aurais fait comme ceci :
SELECT SUM(c1 + c2 + c3) /
 (SUM(IF(c1 != 0, 1, 0) ) +
  SUM(IF(c2 != 0, 1, 0) ) +
  SUM(IF(c3 != 0, 1, 0) ) ) AS RESULT FROM t1 
Mais j'ai peut-être pas capter :)
Ben non, on divise un total non pas par une somme mais par un nombre de lignes, or là, tu n'utilises que des sommes. Si tu observes, dans mes sous-requêtes, j'effectue un COUNT des lignes différentes de zéro. C'est au début que je fais la somme de ces décomptes effectués dans la sous-requête : la valeur ne sera pas la même.

En tous cas, j'ai testé en live en créant une table avec les valeurs suggérées par Cynthia et j'ai obtenu exactement le résultat attendu.

Edit : quoique ton idée, c'est pas totalement fou à la base, il y a peut-être une meilleure solution par là effectivement, je vais regarder ça :-k

Edit 2 : ben c'est surprenant, ta requête fonctionne et du coup est nettement meilleure que la mienne =D>
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

ViPHP
ViPHP | 2291 Messages

30 oct. 2010, 17:42

Salut,

Je fais un total général
SUM(c1 + c2 + c3)


et la je me fou des zéros :)

Puis je compte le nombre de valeurs différentes de zéro
SUM(IF(c1 != 0, 1, 0) ) +
SUM(IF(c2 != 0, 1, 0) ) +
SUM(IF(c3 != 0, 1, 0) )
Une fois les deux valeurs reçue il est simple de faire la moyenne :)
ImageCe que l'on apprend par l'effort reste toujours ancré beaucoup plus longtemps.

Mammouth du PHP | 19672 Messages

30 oct. 2010, 17:47

Tout à fait juste, et ce qui m'a un peu surpris au premier abord était l'absence d'utilisation de COUNT(), mais ta méthode est pour le moins astucieuse :)
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

ViPHP
ViPHP | 2291 Messages

03 nov. 2010, 18:08

:)
ImageCe que l'on apprend par l'effort reste toujours ancré beaucoup plus longtemps.