2

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

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

  • 我的项目名称(共 15 个,我拥有 13 个)
  • 我的商品名称(共 15 个)
  • 我的物品名称(我拥有 13 个)

我的数据库是:

  • 项目: itemId, itemName, ownerId
  • 类别:catId、catName
  • 地图:mapId、itemId、catId

下面的查询获取:类别名称,每个类别的项目 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' 
4

3 回答 3

5

这是一个技巧:计算SUM()已知为 1 或 0 的值的 a 等价于COUNT()值为 1 的行中的 a。您知道布尔比较返回 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 BY您可以在、HAVINGORDER BY子句中使用列别名。这些子句在选择列表中的所有表达式都被求值后运行。

于 2008-11-11T19:27:04.733 回答
4

您可以在 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
于 2008-11-11T19:32:20.447 回答
2
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

请注意,您可以使用HAVINGon 子句owner_item_count,但内部连接会为您处理 item_count。

于 2008-11-11T19:48:35.157 回答