Consulta:contar varios agregados por el artículo
-
07-07-2019 - |
Pregunta
A menudo, usted necesita para mostrar una lista de elementos de base de datos y ciertas cantidades agregadas acerca de cada elemento.Por ejemplo, cuando escriba el texto del título en Stack Overflow, las Preguntas Relacionadas con la lista que aparece.La lista muestra los títulos de las entradas relacionadas y el número total de la cantidad de respuestas para cada título.
Tengo un problema similar, pero la necesidad de utilizar varios agregados.Me gustaría mostrar una lista de elementos en cualquiera de los 3 formatos dependiendo de las opciones de usuario:
- Mi nombre del elemento (15 en total, 13 de mi propiedad)
- Mi nombre del elemento (15 en total)
- Mi nombre del elemento (13 de mi propiedad)
Mi base de datos es:
- elementos:itemId, itemName, ownerId
- categorías:catId, catName
- mapa:mapId, itemId, catId
La consulta siguiente se obtiene:nombre de la categoría, el conde de identificadores de los elementos por categoría
SELECT
categories.catName,
COUNT(map.itemId) AS item_count
FROM categories
LEFT JOIN map
ON categories.catId = map.catId
GROUP BY categories.catName
Esto se obtiene:nombre de la categoría, el conde de identificadores de los elementos por categoría para este owner_id sólo
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
Pero, ¿cómo puedo obtener al mismo tiempo en una sola consulta?I. e.:nombre de la categoría, el conde de identificadores de los elementos por categoría, número de id de elemento de cada categoría para este owner_id sólo
De bono.¿Cómo puedo opcionalmente sólo recuperar donde catId contador != 0 para alguna de estas?En el intento "DONDE item_count <> 0" I get:
MySQL said: Documentation
#1054 - Unknown column 'rid_count' in 'where clause'
Solución
Un truco:el cálculo de un SUM()
de los valores que son conocidos por ser 1 o 0 es equivalente a una COUNT()
de las filas donde el valor es 1.Y usted sabe que una comparación booleana devuelve 1 o 0 (o NULO).
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;
Como para el bono de la pregunta, usted podría simplemente hacer un inner join en lugar de una combinación externa, lo que significaría que sólo las categorías con al menos una fila en map
sería devuelto.
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;
Aquí hay otra solución, que no es tan eficiente, pero te voy a mostrar a explicar por qué tengo el error:
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;
Usted no puede utilizar los alias de columna en la WHERE
la cláusula, porque las expresiones en el WHERE
cláusula son evaluados antes de la expresiones en la lista de selección.En otras palabras, los valores asociados con seleccionar de la lista de expresiones no están disponibles todavía.
Puede utilizar los alias de columna en la GROUP BY
, HAVING
, y ORDER BY
cláusulas.Estas cláusulas se ejecutan después de todas las expresiones de la lista de selección han sido evaluados.
Otros consejos
Puede colarse una declaración CASE dentro de su 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
Tenga en cuenta que podría usar una cláusula HAVING
en owner_item_count
, pero la combinación interna se encarga de item_count por usted.