MySQL 按月获取累计客户交易(不是 SQL 交易)

MySQL Get cumulative customer transactions (not SQL transactions) on a monthly basis

:)

我有一个简单的 table,里面有交易,没什么特别的,我想知道每个月有多少笔交易 "first transactions"。第一次交易是指客户当时第一次购买。

我试图得到的结果是以下形式:

+---------+----------------------------+------------------+
|   Date  |  First Purchases In Month  |  Cumulative Sum  |
+---------+----------------------------+------------------+
| 01/2015 |           10               |       10         |
+---------+----------------------------+------------------+
| 02/2015 |           40               |       50         |
+---------+----------------------------+------------------+

日期格式无所谓,可以是完整日期,反正我稍后会在Java解析。

我发现这个 post 每天都会做类似的事情

How can i get count of customers per day by unique and repeat customer for specific date?

然后我把它变成了这个:

set @csum := 0;
SELECT
    FirstOrderDate, MonthTotal, @csum:= @csum + MonthTotal AS AccumulatedTotal
FROM
(
    SELECT FirstOrderDate, SUM(month_total_new) as MonthTotal
    FROM
    (
        SELECT
            FirstOrderDate, COUNT(q1.consumerId) AS month_total_new
        FROM
        (
            SELECT
                consumerId, MIN(date) AS FirstOrderDate
            FROM
                transaction
            GROUP BY
                consumerId
        ) AS q1
        GROUP BY
            EXTRACT(YEAR FROM q1.FirstOrderDate),
            EXTRACT(MONTH FROM q1.FirstOrderDate)
    ) AS s
    GROUP BY
        EXTRACT(YEAR FROM s.FirstOrderDate),
        EXTRACT(MONTH FROM s.FirstOrderDate)
) AS test;

您可以在此处查看实际效果:http://sqlfiddle.com/#!9/31538/7

结果似乎是正确的,但使用如此多的内部查询似乎并不是最佳实践方法。做这样的事情的建议方法是什么?

此外,当一个月中没有 "first transactions" 而不是那个日期根本不出现时,我想得到 0(比如我们的 fiddle 中只有一个交易的三月不是 "first transaction").

非常感谢您的提前帮助! :)

最简单的方法是按客户汇总以获得每个客户的第一笔交易日期。然后总结一下:

  select year(firstdate) as yyyy, month(firstdate) as mm,
         count(*) as NumFirsts
  from (select consumerid, min(date) as firstdate
        from transaction
        group by consumerid
       ) c
  group by year(firstdate), month(firstdate)
  order by year(firstdate), month(firstdate);

如果您在 java 中阅读此内容,您可能只想在那里计算累计总和。否则,您可以使用变量在 MySQL 中完成:

select c.*, (@s := @s + NumFirsts) as CumeFirsts
from (select year(firstdate) as yyyy, month(firstdate) as mm,
             count(*) as NumFirsts
      from (select consumerid, min(date) as firstdate
            from transaction
            group by consumerid
           ) c
      group by year(firstdate), month(firstdate)
     ) c cross join
     (select @s := 0) params
order by yyyy, mm;

处理首次交易为零的月份也很痛苦。如果您有日历 table 或知道当月有一些交易,这会有所帮助。例如,您可以这样做:

select ym.yyyy, ym.mm, coalesce(NumFirsts, 0) as NumFirsts,
       (@s := @s + coalesce(NumFirsts, 0)) as CumeFirsts
from (select distinct year(date) as yyyy, month(date)
      from transactions
     ) ym left join
     (select year(firstdate) as yyyy, month(firstdate) as mm,
             count(*) as NumFirsts
      from (select consumerid, min(date) as firstdate
            from transaction
            group by consumerid
           ) c
      group by year(firstdate), month(firstdate)
     ) c
     on c.yyyy = ym.yyyy and c.mm = y.mm cross join
     (select @s := 0) params
order by yyyy, mm;