【问题标题】:MySQL: Counting active products that belong to active categories (and optionally to active subcategories)MySQL:计算属于活动类别的活动产品(以及可选的活动子类别)
【发布时间】:2020-05-15 04:47:05
【问题描述】:

我正在使用 MySQL 5.6。我需要获得一个类别列表,其中包含一个产品count 列。到目前为止,这是一个非常简单和微不足道的任务。这里有点复杂:

  • 产品有一个类别,也可以有一个子类别(可选)。
  • 类别子类别产品可以处于活动状态 (flg_public=1) 或禁用 (flg_public=NULL)。

因此,查询应返回满足这些要求的包含产品数量的类别列表:

  • 如果某个类别被禁用,则它不得出现在列表中。
  • 如果某个类别的子类别被禁用,则该子类别中的任何产品都不应计入相应类别的产品计数中。

这是我当前的查询:

SELECT store_cat.id_cat AS id_cat, 
       store_cat.name AS name, 
       COUNT(DISTINCT store_product.id_product) AS q 
FROM   store_cat 
       LEFT JOIN store_product 
              ON store_product.id_cat = store_cat.id_cat 
                 AND store_product.flg_public = 1 
       LEFT JOIN store_subcat 
              ON store_product.id_subcat = store_subcat.id_subcat 
                 AND store_subcat.flg_public = 1 
WHERE  store_cat.flg_public = 1 
GROUP  BY store_cat.id_cat 

我添加了一个 sqlfiddle:http://sqlfiddle.com/#!9/43461b/1

在这个例子中:

  • 子类别裤子属于类别衣服
  • 子类别 裤子 id_subcat=6 已被 flg_public=0 禁用
  • 裤子子类别只有 1 个处于活动状态的产品,但由于该子类别已被禁用,因此在 count 查询中不应考虑这 1 个产品。
  • 如您所见,有 4 个产品使用 id_cat=1,但其中一个产品是 Pantalon Flash id_product=47 属于子类别 Pants @987654333 @ 已被禁用...但仍在考虑中...

衣服类别在金额列中返回 4...但它应该是 3。以下是结果应显示的内容(红色更改):

有什么想法吗?谢谢!

【问题讨论】:

  • 1) 显示小提琴数据的所需结果 2) 指定 MySQl 版本。 3)在您的方案中,数据可能相互矛盾(产品可能直接引用一个子类别并通过类别引用另一个子类别) - 在这种情况下必须如何考虑产品?
  • @Akina 1) 我添加了带有红色校正的屏幕截图 /// 2) 我添加了 mysql 版本 (5.6)。 /// 3) products 可以选择有 id_cat 和 id_subcat... subcat 只能是所选类别的子类别(这在输入表单中控制,并没有为其他目的而特意规范化)。
  • 请看我答案中的小提琴(尤其是中间非分组查询)。根据它 - 建立表(store_product.flg_public, store_subcat.flg_public, 'matched or not')。 9 行 - 每个 flg_public 的 0、1、NULL 和匹配值。这将允许改进解决方案。

标签: mysql sql count left-join mysql-5.6


【解决方案1】:
SELECT store_cat.id_cat AS id_cat, 
       store_cat.name AS name, 
       COUNT(DISTINCT store_product.id_product) AS q 
FROM   store_cat 
       LEFT JOIN store_product 
              ON store_product.id_cat = store_cat.id_cat 
--                 AND store_product.flg_public = 1 
       LEFT JOIN store_subcat 
              ON store_product.id_subcat = store_subcat.id_subcat 
--                 AND store_subcat.flg_public = 1 
WHERE  store_cat.flg_public = 1 
  AND COALESCE(store_subcat.flg_public, 1)
GROUP  BY store_cat.id_cat, store_cat.name ;

fiddle

在小提琴中添加了最少的解释。

【讨论】:

  • 这似乎工作正常,除了特定的情况。如果产品的 flg_public=NULL,它仍将计入您的查询中。添加AND COALESCE(store_product.flg_public, 1) 应该更正它,对吧?
  • @Nick 我在问题的屏幕截图中看到3 代表Snacks,但未标记为红色。
  • @AndresSK 请建立我在问题评论中提出的表格。
  • @Akina 查看 OP 对我的回答的评论。问题中的小吃值不正确。
  • @AndresSK 如果启用了ONLY_FULL_GROUP_BY 服务器选项,则单个GROUP BY store_cat.id_cat 将导致错误,例如SELECT 列表的表达式#x 不在GROUP BY 中。因此,分组表达式中的 2 个字段或将非分组字段包装到某个聚合函数中(例如,MAX() 或 ANY_VALUE())都是安全的。
【解决方案2】:

您的问题是,因为您将LEFT JOIN 更改为store_subcat,即使是具有flg_public = 0 子类别的产品也会包含在输出行中(尝试删除GROUP BY 并更改为SELECT *,您将看到Pantalon Flash 在输出行中,即使来自store_subcat 的字段都是NULL,因为它没有通过flg_public = 1 连接条件)。要解决此问题,您需要添加检查 store_product.id_subcatNULL,或者 store_subcat.id_subcat 不是 NULL(当产品具有具有 flg_public = 1 的子类别时会出现这种情况。更新后的查询:

SELECT store_cat.id_cat AS id_cat, 
       store_cat.name AS name, 
       COUNT(DISTINCT store_product.id_product) AS q 
FROM store_cat 
LEFT JOIN store_product ON store_product.id_cat = store_cat.id_cat 
                       AND store_product.flg_public = 1 
LEFT JOIN store_subcat ON store_product.id_subcat = store_subcat.id_subcat 
                      AND store_subcat.flg_public = 1 
WHERE store_cat.flg_public = 1 
  AND (store_product.id_subcat IS NULL OR store_subcat.id_subcat IS NOT NULL)
GROUP BY store_cat.id_cat 

输出:

id_cat  name        q
1       Clothes     3
2       Accesories  1
3       Snacks      2
4       Other       0
6       Furniture   0
7       Bags        0
9       Pencils     1
10      Medicines   0
11      Candy       0

Demo on SQLFiddle

请注意,Snacks 的正确计数实际上是 2,而不是 3。在 4 个 Snacks 中,Cookie wrappers 具有 flg_public = 0,因此不应包括在内,Pan de espárragos 具有 id_subcat = 1,而 subcat 具有flg_public = 0 所以也不应该包括在内。因此,在 4 种小吃中,应仅包括 2 种。

【讨论】:

  • @Akina 那是因为2 实际上是正确的答案。在 4 种零食中,Cookie wrappers 具有 flg_public = 0,因此不应包括在内,Pan de espárragos 具有 id_subcat = 1,而 subcat 具有 flg_public = 0,因此不应包括在内。所以在 4 种零食中,应该只包括 2 种。
  • @Nick 你是对的,这是我的截图中的错误,我也应该将零食数量从 3 更改为 2。
猜你喜欢
  • 2021-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多