Often you need to show a list of database items and certain aggregate numbers about each item. For instance, when you type the title text on Stack Overflow, the Related Questions list appears. The list shows the titles of related entries and the single aggregated number of quantity of responses for each title.
I have a similar problem but needing multiple aggregates. I'd like to display a list of items in any of 3 formats depending on user options:
My database is:
The query below gets: category name, count of item ids per category
SELECT
categories.catName,
COUNT(map.itemId) AS item_count
FROM categories
LEFT JOIN map
ON categories.catId = map.catId
GROUP BY categories.catName
This one gets: category name, count of item ids per category for this owner_id only
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
But how do i get them at the same time in a single query? I.e.: category name, count of item ids per category, count of item ids per category for this owner_id only
Bonus. How can I optionally only retrieve where catId count != 0 for any of these? In trying "WHERE item_count <> 0" I get:
MySQL said: Documentation
#1054 - Unknown column 'rid_count' in 'where clause'
Here's a trick: calculating a SUM()
of values that are known to be either 1 or 0 is equivalent to a COUNT()
of the rows where the value is 1. And you know that a boolean comparison returns 1 or 0 (or 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;
As for the bonus question, you could simply do an inner join instead of an outer join, which would mean only categories with at least one row in map
would be returned.
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;
Here's another solution, which is not as efficient but I'll show it to explain why you got the 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;
You can't use column aliases in the WHERE
clause, because expressions in the WHERE
clause are evaluated before the expressions in the select-list. In other words, the values associated with select-list expressions aren't available yet.
You can use column aliases in the GROUP BY
, HAVING
, and ORDER BY
clauses. These clauses are run after all the expressions in the select-list have been evaluated.