Somme conditionnelle en mysql

Bonjour à tous, :wink:
j’aimerai faire une somme conditionnelle entre 2 tables en Php/MySql, mais je n’y arrive pas.

Ma première table, nommée Log :

Designation | Quantite
A                     | 1
B                     | 2
A                     | 3

Ma 2ème table, nommée Stock :

Designation | Inventaire
A                     | 5
B                     | 3
C                     | 2

Et je voudrais le résultat suivant :

Designation | EnStock
A                     | 1                           ==> 5 - 1 - 3 = 1
B                     | 1                           ==> 3 - 2 = 1
C                     | 2

J’ai fait la requette suivante :

SELECT Stock.Designation, (Stock.Inventaire-(SELECT IFNULL(SUM(Log.Quantite),0) FROM Log WHERE Log.Designation = Stock.Designation)) AS EnStock FROM Stock WHERE EnStock<3

Le problème vient du fait que je veux tester la valeur de la colonne EnStock (celle que je viens de créer par le calcul) car elle n’est pas reconnus. J’ai l’erreur suivante : :s

Unknown column 'EnStock' in 'where clause'

Qu’est-ce que j’ai fait de mal ?
Merci d’avance de votre aide :slight_smile:
Edité le 14/04/2014 à 17:16

En fait, ta requête multiplie les problèmes.

Déjà, tu traites le résutat de ta sous-requête comme si c’était une colonne, alors qu’un select ramène toujours une structure de type “table” (ou “view”).

Et puis tu essaies d’imbriquer la requête et la sous-requête avec une jointure sur Stock.Designation alors que Stock n’est pas appelée dans la sous-requête. Je sais qu’il est possible de faire des imbrications un peu comme ça, mais c’est des trucs tellement bizarres, spécifiques et complexes que je n’ai jamais eu besoin d’y recourir en 10 ans de carrière.

Donc, le plus simple est de reprendre à zéro.

Tu as 2 tables : “Log” et “Stock”. Tel que tu nous présentes ton problème, tu n’envisages jamais l’hypothèse que tu vas vendre plus d’objets que tu n’avais en stock. C’est une supposition “normale” dans le monde réel mais qu’il faut mentionner explicitement quand tu poses ton problème dans le monde des BDD parce que la BDD se contente de faire des maths et le jour où elle te sortira un résultat négatif, ça ne la dérangera pas.

La condition finale de ta requête suggère que tu es seulement intéressé par les objets dont le stock est inférieur à 3. C’est sensé si tu veux réapprovisionner régulièrement, mais tu n’en as parlé nulle part.

Plutôt que te donner la requête qu’il faut, je préfère t’aiguiller sur les étapes à reconstruire, que tu feras 1 à 1.

  1. créer une requête qui récupère la liste des objets de “Log” et pour chacun la somme d’objets vendus. Ainsi, ta table Log qui ressemble à
Designation | Quantite 
A | 1 
B | 2 
A | 3

deviendra

Designation | Quantite 
A | 4 
B | 2 
  1. Construire une requête qui fait la jointure entre ce résultat précédent et ta table Stock pour obtenir les 3 colonnes suivantes : Designation, Inventaire, Quantite

Remarque : Pour joindre le résultat d’une sous-requete, on fait comme ça


SELECT
Table1.col1,
Table1.machin,
SousRequete.col1,
SousRequete.col2

FROM
Table1,
(SELECT col1, col2 FROM Table2 WHERE blabla) SousRequete

WHERE
Table1.col1 = SousRequete.col1

  1. Modifier la requête obtenue précédemment pour faire la soustraction et appliquer ta condition (moins de 3 objets en stock)
    Edité le 13/04/2014 à 11:17

Merci Jaidee pour ces explications. Il manquait en effet quelques explications, mais tu as cerné le problème de toi même :slight_smile:

J’ai donc suivi ton guide en 3 étapes, ça me donne (d’après mes quelques connaissances en SQL) la requête suivante :

SELECT Stock.Designation, Stock.Inventaire, SumLog.Somme, Stock.Inventaire-SumLog.Somme AS EnStock
FROM Stock, (SELECT Log.Designation, SUM( Log.Quantite ) AS Somme FROM Log GROUP BY Log.Designation) AS SumLog
WHERE Stock.Designation=SumLog.Designation and EnStock<3

Mais j’ai toujours la même erreur :frowning:

De plus, le résultat n’affiche que les articles qui apparaissent dans la table Log (puisqu’on fait une jonction des 2 tables ça me parait normal). Donc si un article a un stock inférieur à 3 mais qu’il n’apparait pas dans Log (pas de vente enregistré encore), il ne s’affichera pas. Enfin je crois … :yeux2:

Qu’en dis-tu ? :etonne2:

“AS” est utilisé pour désigner une colonne. Ici, on est dans la section “FROM” de ta requête principale, donc on utilise une “view” et pas une “colonne”. Retire ce “AS” ! (je te rassure : c’est une erreur qu’on fait tous au début)

Au moment où tu exécutes ta requête, la colonne EnStock n’existe pas encore. Il faut donc que tu remplaces EnStock par i[/i] dans ta “WHERE clause”.

Ok, en effet ça fonctionne. Etrange car au début je n’avais pas mis le AS, et j’avais une erreur comme quoi SumLog était inconnu. J’avais du faire une autre erreur.

J’ai regardé de la doc sur al jointure de tables, notamment pour que tous les résultats de ma table Stock soient affichés, même s’ils ne sont pas dans Log.
J’ai donc construit la requête suivante :

SELECT Stock.Designation, Stock.Inventaire+IFNULL(SumLog.Somme,0)
FROM   Stock 
       LEFT OUTER JOIN (SELECT Log.Designation, SUM(Log.Quantite) AS Somme FROM Log GROUP BY Log.Designation) SumLog
            ON SumLog.Designation = Stock.Designation
WHERE (Stock.Inventaire+IFNULL(SumLog.Somme,0))<3

Qu’en penses-tu ? Est-ce que c’est correct ?

Tu peux :

  • Remplacer le signe “+” par un signe “-” (tu veux faire une soustraction)
  • nommer la colonne résultant de cette expression avec un “AS”

Je pense que c’est correct. Mais j’ai l’habitude d’utiliser des symboles pour remplacer cette syntaxe donc je ne suis pas 100% sûr.

Remarque : puisque tu fais “Stock LEFT OUTER JOIN SumLog”, ce serait plus facile à lire de conserver Stock sur le coté gauche et SumLog sur le coté droit dans ta condition de jointure. Juste une remarque pour la lisibilité, sans impact sur le fonctionnement.

Faire une soustraction encore une fois.

Ok, merci de ton aide :slight_smile:

Encore une question cependant (par curiosité, pour ma culture SQListe). Tu as dit dans un post précédent :

Pourtant, j’ai la requête SQL suivante qui fonctionne :

SELECT DATE_FORMAT(Date, '%M %Y') AS Mois, SUM(Prix) AS Ventes FROM Log WHERE Prix>0 GROUP BY Mois ORDER BY Date

La colonne Mois est correctement identifiée ici. C’est parce que je le met dans un GROUP BY et non dans un WHERE ? Dommage que ça ne fonctionne pas dans le WHERE, c’est pratique ces alias pour simplifier la syntaxe.

Oui, parce que le GROUP BY est évalué a posteriori.

D’ailleurs, tu peux associer une clause “HAVING” à ton “GROUP BY” qui agit comme une “WHERE clause” sur les éléments agrégés. A quelques détails près, tu pourrais remplacer
WHERE Prix>0
par
HAVING Ventes>0

(note : la clause “HAVING” se met tout à la fin)
Edité le 14/04/2014 à 16:21

Ok, merci beaucoup de ton aide.
Subtil le SQL des fois, mais très puissant !