查询:计算每个项目的多个聚合

发布于 2024-07-09 05:47:21 字数 1273 浏览 13 评论 0原文

通常,您需要显示数据库项目的列表以及每个项目的某些汇总数字。 例如,当您在 Stack Overflow 上键入标题文本时,会出现“相关问题”列表。 该列表显示相关条目的标题以及每个标题的回复数量的单个聚合数量。

我有类似的问题,但需要多个聚合。 我想根据用户选项以 3 种格式中的任意一种显示项目列表:

  • 我的项​​目名称(总共 15 个,我拥有 13 个)
  • 我的项目名称(总共 15 个)
  • 我的项目名称(我拥有 13 个)

我的数据库is:

  • items: itemId, itemName,ownerId
  • categories: catId, catName
  • ma​​p: 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

唯憾梦倾城 2024-07-16 05:47:21

这里有一个技巧:计算已知为 1 或 0 的值的 SUM() 相当于计算值为 1 的行的 COUNT()。而且您知道布尔比较返回 1 或 0(或 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;

至于奖励问题,您可以简单地执行内部联接而不是外部联接,这意味着只会返回 map 中至少有一行的类别。

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;

这是另一个解决方案,它的效率不高,但我将用它来解释为什么会出现错误:

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;

您不能在 WHERE 子句中使用列别名,因为 WHERE 中的表达式 子句在选择列表中的表达式之前计算。 换句话说,与选择列表表达式关联的值尚不可用。

您可以在 GROUP BYHAVINGORDER BY 子句中使用列别名。 这些子句在选择列表中的所有表达式都被求值后运行。

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.

北斗星光 2024-07-16 05:47:21

您可以在 SUM() 中添加 CASE 语句:

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

You can sneak a CASE statement inside your 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
墨小墨 2024-07-16 05:47:21
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

请注意,您可以在 owner_item_count 上使用 HAVING 子句,但内部联接会为您处理 item_count。

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

Note that you could use a HAVING clause on owner_item_count, but the inner join takes care of item_count for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文