Question

Il est souvent nécessaire d'afficher une liste d'éléments de base de données et un certain nombre de chiffres globaux pour chaque élément. Par exemple, lorsque vous tapez le texte du titre sur Stack Overflow, la liste des questions connexes apparaît. La liste affiche les titres des entrées liées et le nombre unique de réponses pour chaque titre.

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

  • Nom de mon élément (15 au total, 13 dont je suis propriétaire)
  • Nom de mon élément (15 au total)
  • Nom de mon élément (13 dont je suis propriétaire)

Ma base de données est:

  • éléments : itemId, itemName, ownerId
  • catégories : catId, catName
  • carte : mapId, itemId, catId

La requête ci-dessous obtient: nom de la catégorie, nombre d'identifiants d'élément 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'élément par catégorie pour cet identifiant de 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 puis-je les obtenir en même temps dans une seule requête? I.e .: nom de la catégorie, nombre d'identifiants d'élément par catégorie, nombre d'identifiants d'élément par catégorie pour ce propriétaire uniquement id

Bonus. Comment puis-je éventuellement ne récupérer que le nombre de catId! = 0 pour aucun de ceux-ci? En essayant & «WHERE item_count & Lt; & Gt; 0 & Quot; Je reçois:

MySQL said: Documentation
#1054 - Unknown column 'rid_count' in 'where clause' 
Était-ce utile?

La solution

Voici une astuce: calculer un SUM() des valeurs connues pour être 1 ou 0 équivaut à un COUNT() des lignes où la valeur est 1. Et vous savez qu'une comparaison booléenne renvoie 1 ou 0 (ou NULL).

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;

En ce qui concerne la question bonus, vous pouvez simplement faire une jointure interne au lieu d'une jointure externe, ce qui signifie que seules les catégories comportant au moins une ligne dans map seront renvoyées.

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 moins efficace mais que je vais vous montrer pour expliquer pourquoi vous avez eu 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 d'alias de colonne dans la clause WHERE car les expressions de la clause GROUP BY 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 HAVING, ORDER BY et <=>. Ces clauses sont exécutées une fois que toutes les expressions de la liste de sélection ont été évaluées.

Autres conseils

Vous pouvez insérer une instruction CASE dans votre SUM ():

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
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 HAVING sur owner_item_count, mais la jointure interne prend en charge item_count pour vous.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top