2008-11-11 6 views
2

Souvent, vous devez afficher une liste d'éléments de base de données et certains nombres agrégés concernant chaque élément. Par exemple, lorsque vous tapez le texte du titre sur Dépassement de pile, la liste des questions connexes s'affiche. La liste montre les titres des entrées liées et le nombre agrégé unique de la quantité de réponses pour chaque titre.Requête: comptez plusieurs agrégats par élément

J'ai un problème similaire mais j'ai besoin de plusieurs agrégats. Je voudrais afficher une liste d'éléments dans l'un des 3 formats en fonction des options utilisateur:

  • Mon élément de nom (15 total, 13 appartenant à moi)
  • Nom de mon article (15 au total)
  • Mon point de nom (13 appartenant à moi)

Ma base de données est:

  • articles: Itemid, ITEMNAME, OWNERID
  • catégories: catId, catName
  • carte: mapId, itemId, catId

La requête ci-dessous obtient: nom de la catégorie, le nombre de poste ids par catégorie

SELECT 
    categories.catName, 
    COUNT(map.itemId) AS item_count 
FROM categories 
LEFT JOIN map 
    ON categories.catId = map.catId 
GROUP BY categories.catName 

Celui-ci obtient: nom de la catégorie, nombre d'identifiants d'article par catégorie pour ce propriétaire uniquement

SELECT categories.catName, 
COUNT(map.itemId) AS owner_item_count 
FROM categories 
LEFT JOIN map 
    ON categories.catId = map.catId 
LEFT JOIN items 
    ON items.itemId = map.itemId 
WHERE owner = @ownerId 
GROUP BY categories.catId 

Mais comment les obtenir en même temps dans une seule requête? I.e .: nom de la catégorie, nombre d'ID d'article par catégorie, nombre d'ID d'article par catégorie pour ce propriétaire uniquement

Bonus. Comment puis-je récupérer uniquement si catId compte! = 0 pour l'un de ces? En essayant « OÙ ITEM_COUNT <> 0 » Je reçois:

MySQL said: Documentation 
#1054 - Unknown column 'rid_count' in 'where clause' 

Répondre

5

Voici une astuce: le calcul d'une SUM() des valeurs qui sont connues pour être 1 ou 0 est équivalent à un COUNT() des lignes où la valeur est 1 Et vous savez qu'une comparaison booléenne renvoie 1 ou 0 (ou NULL). Quant à la question bonus

SELECT c.catname, COUNT(m.catid) AS item_count, 
    SUM(i.ownerid = @ownerid) AS owner_item_count 
FROM categories c 
    LEFT JOIN map m USING (catid) 
    LEFT JOIN items i USING (itemid) 
GROUP BY c.catid; 

, vous pouvez simplement faire une jointure interne au lieu d'une jointure externe, ce qui voudrait dire que les catégories avec au moins une ligne dans map serait retourné.

SELECT c.catname, COUNT(m.catid) AS item_count, 
    SUM(i.ownerid = @ownerid) AS owner_item_count 
FROM categories c 
    INNER JOIN map m USING (catid) 
    INNER JOIN items i USING (itemid) 
GROUP BY c.catid; 

Voici une autre solution, ce qui est pas aussi efficace, mais je vais le montrer pour expliquer pourquoi vous avez l'erreur:

SELECT c.catname, COUNT(m.catid) AS item_count, 
    SUM(i.ownerid = @ownerid) AS owner_item_count 
FROM categories c 
    LEFT JOIN map m USING (catid) 
    LEFT JOIN items i USING (itemid) 
GROUP BY c.catid 
HAVING item_count > 0; 

Vous ne pouvez pas utiliser des alias de colonne dans la clause WHERE, parce que Les expressions de la clause WHERE sont évaluées avant les expressions de la liste de sélection. En d'autres termes, les valeurs associées aux expressions de liste de sélection ne sont pas encore disponibles.Vous pouvez utiliser des alias de colonne dans les clauses GROUP BY, HAVING et ORDER BY. Ces clauses sont exécutées après que toutes les expressions de la liste de sélection ont été évaluées.

4

Vous pouvez glisser une instruction CASE dans votre SOMME():

SELECT categories.catName, 
    COUNT(map.itemId) AS item_count, 
    SUM(CASE WHEN owner= @ownerid THEN 1 ELSE 0 END) AS owner_item_count 
FROM categories 
LEFT JOIN map ON categories.catId = map.catId 
LEFT JOIN items ON items.itemId = map.itemId 
GROUP BY categories.catId 
HAVING COUNT(map.itemId) > 0 
2
SELECT categories.catName, 
    COUNT(map.itemId) AS item_count, 
    COUNT(items.itemId) AS owner_item_count 
FROM categories 
INNER JOIN map 
    ON categories.catId = map.catId 
LEFT JOIN items 
    ON items.itemId = map.itemId 
    AND items.owner = @ownerId 
GROUP BY categories.catId 

Notez que vous pouvez utiliser une clause sur HAVINGowner_item_count, mais la jointure interne prend soin de ITEM_COUNT pour vous.

Questions connexes