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' 
¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top