【问题标题】:MySQL sales data group by monthly averageMySQL 销售数据组(按月平均)
【发布时间】:2016-10-14 17:59:29
【问题描述】:

我有一个包含以下列的销售表:

mysql> select * from sales;
+-------------+--------+------------+
| customer_id | amount | date       |
+-------------+--------+------------+
|           1 |     12 | 2015-01-01 |
|           1 |      1 | 2015-01-02 |
|           1 |    663 | 2015-02-12 |
|           2 |     22 | 2015-01-03 |
|           2 |     21 | 2015-02-12 |
|           2 |     11 | 2015-02-12 |
|           2 |      9 | 2015-04-12 |
+-------------+--------+------------+

我可以使用这个查询来接近我想要的:

SELECT
  customer_id,
  sum(if(month(date) = 1, amount, 0))  AS Jan,
  sum(if(month(date) = 2, amount, 0))  AS Feb,
  sum(if(month(date) = 3, amount, 0))  AS Mar,
  sum(if(month(date) = 4, amount, 0))  AS Apr,
  sum(if(month(date) = 5, amount, 0))  AS May,
  sum(if(month(date) = 6, amount, 0))  AS Jun,
  sum(if(month(date) = 7, amount, 0))  AS Jul,
  sum(if(month(date) = 8, amount, 0))  AS Aug,
  sum(if(month(date) = 9, amount, 0))  AS Sep,
  sum(if(month(date) = 10, amount, 0)) AS Oct,
  sum(if(month(date) = 11, amount, 0)) AS Nov,
  sum(if(month(date) = 12, amount, 0)) AS `Dec`
FROM sales
GROUP BY customer_id;

所需的输出格式:

+-------------+------+------+------+------+------+------+------+------+------+------+------+------+
| customer_id | Jan  | Feb  | Mar  | Apr  | May  | Jun  | Jul  | Aug  | Sep  | Oct  | Nov  | Dec  |
+-------------+------+------+------+------+------+------+------+------+------+------+------+------+
|           1 |   13 |  663 |    0 |    0 |    0 |    0 |    0 |    0 |    0 |    0 |    0 |    0 |
|           2 |   22 |   32 |    0 |    9 |    0 |    0 |    0 |    0 |    0 |    0 |    0 |    0 |
+-------------+------+------+------+------+------+------+------+------+------+------+------+------+

但是我想要每月的平均值,当我将 sum 更改为 avg 时,我没有得到平均值。

SELECT
  customer_id,
  avg(if(month(date) = 1, amount, 0))  AS Jan,
  avg(if(month(date) = 2, amount, 0))  AS Feb,
  avg(if(month(date) = 3, amount, 0))  AS Mar,
  avg(if(month(date) = 4, amount, 0))  AS Apr,
  avg(if(month(date) = 5, amount, 0))  AS May,
  avg(if(month(date) = 6, amount, 0))  AS Jun,
  avg(if(month(date) = 7, amount, 0))  AS Jul,
  avg(if(month(date) = 8, amount, 0))  AS Aug,
  avg(if(month(date) = 9, amount, 0))  AS Sep,
  avg(if(month(date) = 10, amount, 0)) AS Oct,
  avg(if(month(date) = 11, amount, 0)) AS Nov,
  avg(if(month(date) = 12, amount, 0)) AS `Dec`
FROM sales
GROUP BY customer_id;

产出(不是每月平均):

+-------------+--------+----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
| customer_id | Jan    | Feb      | Mar    | Apr    | May    | Jun    | Jul    | Aug    | Sep    | Oct    | Nov    | Dec    |
+-------------+--------+----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|           1 | 4.3333 | 221.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 |
|           2 | 5.5000 |   8.0000 | 0.0000 | 2.2500 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 |
+-------------+--------+----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+

我有点想弄清楚发生了什么,有人提供一些建议吗?谢谢

CREATE TABLE `sales` (
  `customer_id` int(11) NOT NULL,
  `amount` int(11) DEFAULT NULL,
  `date` date DEFAULT NULL
) 

INSERT INTO `sales` VALUES (1,12,'2015-01-01'),(1,1,'2015-01-02'),(1,663,'2015-02-12'),(2,22,'2015-01-03'),(2,21,'2015-02-12'),(2,11,'2015-02-12'),(2,9,'2015-04-12');

【问题讨论】:

  • 尝试在 avg 中将 0 更改为 NULL:avg(if(month(date) = 1, amount, NULL))
  • 根据其他现有记录在一个月内插入任意多个0,您会偏向您的平均值。也许更好group by customer_id, MONTH(date)
  • 考虑处理表示层/应用程序级代码中的数据显示问题(如果可用)

标签: mysql sql


【解决方案1】:

问题是0s。不会影响sum(),但会影响平均值。您可以将它们更改为NULL

SELECT customer_id,
       avg(if(month(date) = 1, amount, NULL))  AS Jan,
       avg(if(month(date) = 2, amount, NULL))  AS Feb,
       avg(if(month(date) = 3, amount, NULL))  AS Mar,
       avg(if(month(date) = 4, amount, NULL))  AS Apr,
       avg(if(month(date) = 5, amount, NULL))  AS May,
       avg(if(month(date) = 6, amount, NULL))  AS Jun,
       avg(if(month(date) = 7, amount, NULL))  AS Jul,
       avg(if(month(date) = 8, amount, NULL))  AS Aug,
       avg(if(month(date) = 9, amount, NULL))  AS Sep,
       avg(if(month(date) = 10, amount, NULL)) AS Oct,
       avg(if(month(date) = 11, amount, NULL)) AS Nov,
       avg(if(month(date) = 12, amount, NULL)) AS `Dec`
FROM sales
GROUP BY customer_id;

作为说明:我更喜欢case,因为它是 ANSI 标准,所以我会这样写:

       avg(case when month(date) = 1 then amount end) as Jan,

【讨论】:

  • 谢谢,Mike 也发现了这一点并添加了评论。答案有效,但也解释了我在平均值中包含的 0 周围缺少什么。
  • 3,3,0 的平均值为 (3+3+0)/3,但 3,3,NULL 的平均值为 (3+3)/2。它在 avg 计算中不考虑 NULL,但会考虑 0。
【解决方案2】:

试试这样的:

SELECT
    customer_id,
  if(month(hlp_tab2.date) = 1, hlp_tab2.amount, 0)  AS Jan,
  if(month(hlp_tab2.date) = 2, hlp_tab2.amount, 0)  AS Feb,
  if(month(hlp_tab2.date) = 3, hlp_tab2.amount, 0)  AS Mar,
  if(month(hlp_tab2.date) = 4, hlp_tab2.amount, 0)  AS Apr,
  if(month(hlp_tab2.date) = 5, hlp_tab2.amount, 0)  AS May,
  if(month(hlp_tab2.date) = 6, hlp_tab2.amount, 0)  AS Jun,
  if(month(hlp_tab2.date) = 7, hlp_tab2.amount, 0)  AS Jul,
  if(month(hlp_tab2.date) = 8, hlp_tab2.amount, 0)  AS Aug,
  if(month(hlp_tab2.date) = 9, hlp_tab2.amount, 0)  AS Sep,
  if(month(hlp_tab2.date) = 10, hlp_tab2.amount, 0) AS Oct,
  if(month(hlp_tab2.date) = 11, hlp_tab2.amount, 0) AS Nov,
  if(month(hlp_tab2.date) = 12, hlp_tab2.amount, 0) AS `Dec`
FROM (
    SELECT
        hlp_tab.customer_id,
        avg(hlp_tab.amount) 'amount',
        hlp_tab.date
    FROM (
        SELECT
          customer_id,
          amount,
          month(date) 'date'
        FROM sales
    ) hlp_tab
    group by
        hlp_tab.customer_id,
        hlp_tab.date
) hlp_tab2

【讨论】:

    【解决方案3】:
    SELECT 
    customer_id, 
    SUM(Jan) AS Jun,
    SUM(Feb) AS Feb,
    SUM(Mar) AS Mar,
    SUM(Apr) AS Apr,
    SUM(May) AS May,
    SUM(Jun) AS Jun,
    SUM(Jul) AS Jul,
    SUM(Aug) AS Aug,
    SUM(Sep) AS Sep,
    SUM(Oct) AS Oct,
    SUM(Nov) AS Nov,
    SUM(`Dec`) AS `Dec`
    FROM (
    SELECT
        customer_id,
        avg(if(month(date) = 1, amount, 0))  AS Jan,
        avg(if(month(date) = 2, amount, 0))  AS Feb,
        avg(if(month(date) = 3, amount, 0))  AS Mar,
        avg(if(month(date) = 4, amount, 0))  AS Apr,
        avg(if(month(date) = 5, amount, 0))  AS May,
        avg(if(month(date) = 6, amount, 0))  AS Jun,
        avg(if(month(date) = 7, amount, 0))  AS Jul,
        avg(if(month(date) = 8, amount, 0))  AS Aug,
        avg(if(month(date) = 9, amount, 0))  AS Sep,
        avg(if(month(date) = 10, amount, 0)) AS Oct,
        avg(if(month(date) = 11, amount, 0)) AS Nov,
        avg(if(month(date) = 12, amount, 0)) AS `Dec`
      FROM sales
      GROUP BY customer_id, month(date)
    ) AS a GROUP BY customer_id
    

    【讨论】:

      【解决方案4】:

      一个快速的解决方法是:

          SELECT 
        customer_id,
        MAX(if(`month` = 1, amount, 0))  AS Jan,
        MAX(if(`month` = 2, amount, 0))  AS Feb,
        MAX(if(`month` = 3, amount, 0))  AS Mar,
        MAX(if(`month` = 4, amount, 0))  AS Apr,
        MAX(if(`month` = 5, amount, 0))  AS May,
        MAX(if(`month` = 6, amount, 0))  AS Jun,
        MAX(if(`month` = 7, amount, 0))  AS Jul,
        MAX(if(`month` = 8, amount, 0))  AS Aug,
        MAX(if(`month` = 9, amount, 0))  AS Sep,
        MAX(if(`month` = 10, amount, 0)) AS Oct,
        MAX(if(`month` = 11, amount, 0)) AS Nov,
        MAX(if(`month` = 12, amount, 0)) AS `Dec`
      FROM
      (
        SELECT
          customer_id,
          (month(date)) `month`,
          AVG(amount) amount
        FROM sales
        GROUP BY customer_id,(month(date))
      ) AS T
      GROUP BY customer_id;
      

      SQLFiddle

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多