【问题标题】:MySQL Adding COUNT( ) valuesMySQL 添加 COUNT() 值
【发布时间】:2014-08-08 14:27:02
【问题描述】:

编辑: SQL Fiddle here

我正在处理产品 Feed。我得到一份报价清单;

  • 每个优惠都有 1 个产品
  • 每个产品都属于一个类别
  • 一个类别可以是另一个类别的子类别

我有三个表(我只会向您显示相关行)

优惠:

OFFERS
___________________
| id | product_id |
-------------------
|  1 |         16 |
-------------------
|  2 |         54 |
-------------------
|  3 |         52 |
-------------------
|  4 |         20 |
-------------------
|  5 |          7 |
-------------------
|  6 |          5 |
-------------------

产品:

PRODUCTS
_______________
| id | cat_id |
---------------
| 16 |      1 |
---------------
| 54 |      3 |
---------------
| 52 |      4 |
---------------
| 20 |      1 |
---------------
|  7 |     15 |
---------------
|  5 |      3 |
---------------

分类:

CATEGORIES
_____________________________________________________________
| id | display_name | original_name | subcat_of | is_active |
-------------------------------------------------------------
|  1 | Cars         | automobiles   |         0 |         1 |
-------------------------------------------------------------
|  2 |              | motorcycles   |         0 |         0 |
-------------------------------------------------------------
|  3 | Muscle cars  | muscle-cars   |         1 |         1 |
-------------------------------------------------------------
|  4 | Hybrid cars  | treehugwagons |         1 |         1 |
-------------------------------------------------------------

我必须编写两个查询。第一个需要

  • 返回名称并计算给定主类别及其子类别的报价数量
  • 但前提是该主要类别处于活动状态
  • 如果一个类别没有 display_name,则使用 original_name

我想我有这个:

SELECT
    offers.id AS offer_id,
    product_id,
    products.cat_id,
    CASE
        WHEN categories.display_name <> ''
        THEN categories.display_name
        ELSE categories.original_name
    END AS cat_name,
    COUNT(offers.id) as num_offers
FROM
    offers
INNER JOIN
    products
    ON
    product_id = products.id
INNER JOIN
    categories
    ON
    cat_id = categories.id
WHERE
    categories.is_active = 1
    AND
    (categories.id = :cat_id OR categories.subcat_of = :cat_id)
GROUP BY
    cat_name
ORDER BY
    cat_name ASC

我很确定这个查询远非理想,但就目前而言,它有效。

这是我需要的第二个查询给我带来了问题。那个人需要:

  • 返回名称并计算给定主要类别及其子类别的报价数量并返回每个主要类别的这些计数的总和
  • 但前提是该主要类别处于活动状态
  • 如果一个类别没有 display_name,则使用 original_name

我可以使用一些 PHP 自己进行求和,但如果在 SQL 中无法完成这么简单的事情,我会感到惊讶。

【问题讨论】:

  • 您是否介意提供您所做的示例:sqlfiddle.com
  • 你能发布写第二个查询的尝试吗?如果你有一个起点,人们会更容易帮助你:) 编辑:@ThomasJunk 打败了我!
  • 您能否在您的数据库中使用第一个查询创建一个视图并使用SELECT SUM(sum_offers) FROM your_view GROUP BY cat_name 从那里获取第二个视图的总和?希望我理解您的要求,我不确定主要类别是什么(是一个没有子类别的类别,您想要它和所有子类别的总和?)。
  • 显然我在写上面的时候喝醉了。我在问:主类是一个不是子类的类吗?您想要主类别及其所有子类别的报价总和?
  • 哇,你醒得很快:P确实,这就是我想做的。

标签: mysql sql


【解决方案1】:

我相信这是可能的并且相当简单,假设您没有子子类别:

  SELECT CASE 
           WHEN c_main.display_name <> ''
           THEN c_main.display_name
           ELSE c_main.original_name
         END cat_name,
         COUNT(o.id) as num_offers
    FROM offers o
    JOIN products p
      ON o.product_id = p.id
    JOIN categories c
      ON p.cat_id = c.id
     AND (c.id = :cat_id OR c.subcat_of = :cat_id)
  /* AND c.is_active = 1 /* Include if necessary */
    JOIN categories c_main
      ON c_main.id = :cat_id
     AND c_main.is_active = 1 
GROUP BY cat_name
ORDER BY cat_name ASC

你的第一个查询我会写成:

  SELECT CASE 
           WHEN c.display_name <> ''
           THEN c.display_name
           ELSE c.original_name
         END cat_name,
         COUNT(o.id) as num_offers
    FROM offers o
    JOIN products p
      ON o.product_id = p.id
    JOIN categories c
      ON p.cat_id = c.id
     AND (c.id = :cat_id OR c.subcat_of = :cat_id)
     AND c.is_active = 1
GROUP BY cat_name
ORDER BY cat_name ASC

顺便说一句:

我也会考虑NULL把空的display_names换掉,然后你可以替换

CASE 
  WHEN c_main.display_name <> ''
  THEN c_main.display_name
  ELSE c_main.original_name
END cat_name

与:

COALESCE(c_main.display_name, c_main.original_name) cat_name

【讨论】:

  • 在 products 表中有一个 cat_id = 15,所以至少有 15 个类别。可以肯定地说没有子子类别吗?如果有轿跑肌肉车类别怎么办?您的解决方案仅适用于 2 个级别,如果 OP 没问题,我的回答是针对更一般的情况。
  • @Narmer 很公平,OP 表示他们的第一个查询“关闭”这一事实表明只有两个级别!是的,更一般的情况需要一个函数/过程。
  • 第一个查询不关心类别层次结构。它只是选择每个类别的报价总和,无论它是主类别还是子类别(或子子类别......)。在小提琴中检查它。
  • @Narmer 你错了。请参阅WHERE 子句中的(categories.id = :cat_id OR categories.subcat_of = :cat_id)。这清楚地表明了 2 级层次结构。
  • 呃,对了...错过了。此外,还有返回名称并计算给定主要类别及其子类别的报价数量。只有 OP 可以定义它是否是 2 级或更高级别的层次结构(对于非英语为母语的人来说,这是最难拼出的单词之一,我总是必须用谷歌搜索)。
【解决方案2】:

由于 MySQL 不支持递归查询,因此无法在 MySQL 中完成。您有三个选择:

  1. 使用some complex function 模拟递归/分层查询。 (Related)
  2. 切换到supports recursive queries using CTE的SQL Server。
  3. 写一点PHP。

这取决于你:)

作为旁注,我在这里留下一张有趣的幻灯片 Models for Hierarchical data with SQL and PHP,由 SO 用户 @Bill Karwin 撰写,可能适合您的情况。

【讨论】:

  • 嗯,看我的回答,但是它假设只有一层嵌套。
猜你喜欢
  • 2020-10-31
  • 1970-01-01
  • 2019-09-16
  • 2010-12-02
  • 1970-01-01
  • 1970-01-01
  • 2011-07-23
  • 2010-12-11
  • 2017-11-04
相关资源
最近更新 更多