查询:计算每个项目的多个聚合
通常,您需要显示数据库项目的列表以及每个项目的某些汇总数字。 例如,当您在 Stack Overflow 上键入标题文本时,会出现“相关问题”列表。 该列表显示相关条目的标题以及每个标题的回复数量的单个聚合数量。
我有类似的问题,但需要多个聚合。 我想根据用户选项以 3 种格式中的任意一种显示项目列表:
- 我的项目名称(总共 15 个,我拥有 13 个)
- 我的项目名称(总共 15 个)
- 我的项目名称(我拥有 13 个)
我的数据库is:
- items: itemId, itemName,ownerId
- categories: catId, catName
- map: mapId, itemId, catId
下面的查询获取:category name,每个类别的项目 ID 计数
SELECT
categories.catName,
COUNT(map.itemId) AS item_count
FROM categories
LEFT JOIN map
ON categories.catId = map.catId
GROUP BY categories.catName
这个获取:类别名称、仅针对此 Owner_id 的每个类别的项目 ID 计数
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
但是如何在单个查询中同时获取它们? 即:类别名称、每个类别的项目 id 计数、每个类别的项目 id 计数(仅针对此 Owner_id
奖励)。 我如何选择性地仅检索其中任何一个的 catId count != 0 的位置? 在尝试“WHERE item_count <> 0”时我得到:
MySQL said: Documentation
#1054 - Unknown column 'rid_count' in 'where clause'
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 item's name (15 total, 13 owned by me)
- My item's name (15 total)
- My item's name (13 owned by me)
My database is:
- items: itemId, itemName, ownerId
- categories: catId, catName
- map: mapId, itemId, catId
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'
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这里有一个技巧:计算已知为 1 或 0 的值的
SUM()
相当于计算值为 1 的行的COUNT()
。而且您知道布尔比较返回 1 或 0(或 NULL)。至于奖励问题,您可以简单地执行内部联接而不是外部联接,这意味着只会返回
map
中至少有一行的类别。这是另一个解决方案,它的效率不高,但我将用它来解释为什么会出现错误:
您不能在
WHERE
子句中使用列别名,因为WHERE 中的表达式
子句在选择列表中的表达式之前计算。 换句话说,与选择列表表达式关联的值尚不可用。您可以在
GROUP BY
、HAVING
和ORDER BY
子句中使用列别名。 这些子句在选择列表中的所有表达式都被求值后运行。Here's a trick: calculating a
SUM()
of values that are known to be either 1 or 0 is equivalent to aCOUNT()
of the rows where the value is 1. And you know that a boolean comparison returns 1 or 0 (or NULL).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.Here's another solution, which is not as efficient but I'll show it to explain why you got the error:
You can't use column aliases in the
WHERE
clause, because expressions in theWHERE
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
, andORDER BY
clauses. These clauses are run after all the expressions in the select-list have been evaluated.您可以在 SUM() 中添加 CASE 语句:
You can sneak a CASE statement inside your SUM():
请注意,您可以在
owner_item_count
上使用HAVING
子句,但内部联接会为您处理 item_count。Note that you could use a
HAVING
clause onowner_item_count
, but the inner join takes care of item_count for you.