2010-04-28 6 views
6

Je suis sûr que cela a une réponse très simple, mais je n'arrive pas à la trouver (je ne sais pas quoi chercher!) . Un compte/groupe standard par requête peut ressembler à ceci:MYSQL: COUNT avec GROUP BY, LEFT JOIN et la clause WHERE ne renvoie pas de valeurs

SELECT COUNT(`t2`.`name`) 
FROM `table_1` `t1` 
    LEFT JOIN `table_2` `t2` ON `t1`.`key_id` = `t2`.`key_id` 
WHERE `t1`.`another_column` = 123 

et cela fonctionne comme prévu, le retour 0 si aucune ligne se trouvent. Cependant:

SELECT COUNT(`t2`.`name`) 
FROM `table_1` `t1` 
    LEFT JOIN `table_2` `t2` ON `t1`.`key_id` = `t2`.`key_id` 
WHERE `t1`.`another_column` = 123 
GROUP BY `t1`.`any_col` 

ne fonctionne que s'il y a au moins une rangée dans table_1 et échoue lamentablement retourner un jeu de résultats vide s'il n'y a aucune ligne. Je voudrais vraiment que cela retourne 0! Quelqu'un m'éclaire-t-il là-dessus? La bière peut être fournie en échange si vous êtes à Londres ;-)

Répondre

4

La raison pour laquelle elle renvoie zéro lignes est que vous groupez sur une valeur dans table_1. SInce il n'y a pas de valeurs dans table_1, il n'y a pas de lignes à retourner. Dit autrement, si vous revenez t1.any_col dans votre requête du GROUP BY comme ceci:

SELECT `t1`.`any_col`, COUNT(`t2`.`name`) 
FROM `table_1` `t1` 
    LEFT JOIN `table_2` `t2` ON `t1`.`key_id` = `t2`.`key_id` 
WHERE `t1`.`another_column` = 123 
GROUP BY `t1`.`any_col` 

Que afficherait pour t1.any_col quand il n'y avait pas de lignes? La seule façon d'obtenir ce que vous voulez est d'unir vos résultats avec une autre requête qui ne vérifie aucune ligne dans table_1. Dans cet exemple, j'utilise la vue INFORMATION_SCHEMA simplement pour avoir quelque chose contre lequel je peux interroger.

SELECT COUNT(`t2`.`name`) 
FROM `table_1` `t1` 
    LEFT JOIN `table_2` `t2` ON `t1`.`key_id` = `t2`.`key_id` 
WHERE `t1`.`another_column` = 123 
GROUP BY `t1`.`any_col` 
UNION ALL 
SELECT 0 
FROM INFORMATION_SCHEMA.TABLES 
Where Not Exists(Select 1 From `table_1`) 
LIMIT 1 
+0

Pourquoi le premier exemple fonctionne-t-il bien? Tout ce qui manque est la clause WHERE, il ne peut toujours pas y avoir de lignes et ça marchera très bien ... –

+0

@Paul Norman - Le premier exemple fonctionne car il y a clairement des lignes dans la table_1. Le troisième exemple ne fonctionne pas car, apparemment, il n'y a pas de lignes dans table_1 qui ont une valeur 123 pour 'another_column'. Si la requête sans le regroupement ne renvoie aucune ligne, elle ne renverra pas de lignes avec le regroupement. – Thomas

3

est ici la meilleure solution:

SELECT COUNT(*) FROM 
(SELECT `t2`.`name` 
FROM `table_1` `t1` 
    LEFT JOIN `table_2` `t2` ON `t1`.`key_id` = `t2`.`key_id` 
WHERE `t1`.`another_column` = 123 
GROUP BY `t1`.`any_col`) tmp 

Vous avez juste besoin d'envelopper SELECT COUNT(*) autour de la requête. Le problème est que COUNT() change du sens "donnez-moi le nombre de lignes dans le jeu de résultats" à une fonction agrégée qui signifie "donnez-moi le nombre de lignes pour chaque groupe qui correspond à mes critères" lorsqu'il est utilisé avec le GROUP BY clause. Dans votre cas, puisqu'il n'y a pas de ligne pour le groupe où another_column = 123, rien n'est retourné.

Si vous encapsulez cela dans un autre SELECT COUNT(*), vous dites encore, "donnez-moi le nombre de lignes dans le jeu de résultats". Dans la première requête, COUNT() fonctionne avec GROUP BY. Toutefois, si aucun critère n'est spécifié, vous obtenez au moins une ligne renvoyée par table_1. Comme il n'y a pas d'enregistrements table_2 correspondants, NULL est évalué à 0 pour COUNT(). N'utilisez pas la première requête. Bien que cela renvoie ce que vous attendez, ce n'est que par hasard. Pour que la requête soit significative, vous devez spécifier des critères pour t1.another_column dans la clause WHERE.

La deuxième requête fonctionne car vous demandez un nombre de lignes du jeu de résultats. Comme il n'y a pas de lignes où t1.another_column = 123, il y a 0 lignes retournées, et COUNT() est évalué à 0.

+0

Ceci malheureusement seulement me dit combien de «groupes» uniques il y a. Donc s'il n'y a qu'une seule valeur 'any_col' distincte dans' table_1', mais 5 lignes de données où 'any_col' = 5 cela retournera 1, pas 5 comme requis (parce que le SELECT imbriqué ne retournerait qu'une ligne). –

+0

@Paul, s'il vous plaît actualiser votre navigateur. J'avais réparé ça. Notez que COUNT() est uniquement utilisé dans la requête externe. –

+0

J'ai fait ce changement moi-même, mais je pense toujours (ou plutôt j'ai testé) que GROUP BY dans la requête imbriquée signifie qu'une seule ligne sera retournée si les seules données de la table ont une seule valeur 'any_col' (ie Si chaque rangée a 'any_col' = 5, alors une seule ligne sera retournée par la sélection imbriquée - comme vous pouvez le prévoir - et il s'ensuit que le comptage de ces données produit seulement 1, pas le 5 requis. La solution ci-dessus fonctionne de toute façon, jamais pensé à ça! Merci pour votre aide. Il est difficile d'être clair dans cette minuscule boîte! –