2010-09-09 4 views
2

J'ai 2 tables dans ma base de données: article et catégorie. Les éléments peuvent être actifs ou inactifs et posséder un ID de catégorie associé à l'ID d'un enregistrement dans la table de catégories.mysql left joindre le problème avec la clause SUM et WHERE

je veux effectuer une requête pour afficher toutes les catégories, avec le coût total des éléments actifs pour la catégorie

Donc, mon but est de retourner quelque chose qui ressemble à ceci:

+--------+------------+---------------+ 
    | id  | cat_name | total_cost | 
    +--------+------------+---------------+ 
    |  1 | cat 1  | 12   | 
    |  2 | cat 2  | 0    | 
    |  3 | cat 3  | 45   | 
    +--------+------------+---------------+ 

Ma première requête:

SELECT a.*, 
    SUM(b.cost) AS total_cost 
    FROM categories a LEFT JOIN items b 
    ON(a.id = b.category_id) 
    GROUP BY a.category_name 

fonctionne bien, mais il retourne des éléments NULL au lieu de 0, et utilise tous les éléments indépendamment de l'actif/dans actif:

+--------+------------+---------------+ 
    | id  | cat_name | total_cost | 
    +--------+------------+---------------+ 
    |  1 | cat 1  | 44   | 
    |  2 | cat 2  | NULL   | 
    |  3 | cat 3  | 87   | 
    +--------+------------+---------------+ 

ma deuxième requête adresses les valeurs NULL:

SELECT a.*, 
    SUM(IF(b.cost IS NULL, 0, b.cost)) AS total_cost 
    FROM categories a LEFT JOIN items b 
    ON(a.id = b.category_id) 
    GROUP BY a.category_name 

et se révèle comme ceci:

+--------+------------+---------------+ 
    | id  | cat_name | total_cost | 
    +--------+------------+---------------+ 
    |  1 | cat 1  | 44   | 
    |  2 | cat 2  | NULL   | 
    |  3 | cat 3  | 87   | 
    +--------+------------+---------------+ 

Donc, dans mon petit cerveau inutile j'essayer la requête suivante, en ajoutant une clause WHERE sur la table b où active doit = ​​1 (vrai)

SELECT a.*, 
    SUM(IF(b.cost IS NULL, 0, b.cost)) AS total_cost 
    FROM categories a LEFT JOIN items b 
    ON(a.id = b.category_id) 
    WHERE b.active = 1 
    GROUP BY a.category_name 

et je reçois les éléments suivants:

+--------+------------+---------------+ 
    | id  | cat_name | total_cost | 
    +--------+------------+---------------+ 
    |  1 | cat 1  | 12   | 
    |  3 | cat 3  | 45   | 
    +--------+------------+---------------+ 

afin que vous pouvez proprement parler, je voudrais retourner toute la gamme des catégories, même lorsque la table de droite Aucun résultat correspondant ... Tout prend pour un million imaginaire points cool?

Répondre

6

Utilisation:

SELECT c.id, 
      c.cat_name, 
      COALESCE(SUM(i.cost), 0) AS total_cost 
    FROM CATEGORIES c 
LEFT JOIN ITEMS i ON i.category_id = c.category_id 
       AND i.active = 1 
GROUP BY c.id, c.cat_name 
+0

cela fonctionne, pas de problème. mais dans mysql vous n'avez pas besoin de grouper par 'cat_name'. 'id' est suffisant. Si vous voulez qu'il soit plus efficace et conforme à la norme SQL, utilisez 'max (nom.cat_c) ou un groupe similaire par fonction dans les expressions de colonne. –

+0

@Imre L: L'utilisation de MAX serait masquée s'il y avait deux valeurs cat_name ou plus associées au même identifiant, dans la mesure du possible. Il n'y a rien d'inhabituel à définir des colonnes dans le groupe qui n'ont pas de fonctions agrégées, et en supposant que la valeur d'id est unique, c'est un choix personnel (bien que MAX/etc implique qu'il pourrait y avoir des doublons). –

+0

Bravo bon monsieur - accordez-vous une grande tape sur le sac et autant de points cool imaginaires que vous pouvez porter. Je dois faire un peu de lecture dans cette déclaration coalesce pour comprendre pleinement ce qui se passe. – Beans

1

Essayez ceci:

SELECT a.*, 
    SUM(Case B.Active When 1 Then b.cost else 0 End) AS total_cost 
    FROM categories a 
     LEFT JOIN items b 
     ON b.category_id = a.id 
    GROUP BY a.category_name 

ou ceci:

SELECT a.*, SUM(b.cost) AS total_cost 
    FROM categories a 
     LEFT JOIN items b 
     ON b.category_id = a.id 
      And B.Active = 1 
    GROUP BY a.category_name 
+0

Vous êtes également tout à fait Bodacious et gagner des points frais imaginaires gazillion - merci. Les deux ont beaucoup de sens, et bien sûr, travaillent. Avez-vous une idée de la raison pour laquelle une méthode serait «meilleure» qu'une autre? Du point de vue de la lisibilité, je trouve plus facile de comprendre la première requête, même si elle est plus verbeuse. – Beans

+0

En outre, le premier renvoie des valeurs nulles au lieu de zéro pour le total_cost mais c'est une solution facile. Et je pense que le second devrait avoir b.active = 1, au lieu de b.cost = 1 – Beans

+0

ahh oui, typo ... b.active il devrait être! –