情弱エンジニアのなかのblog

一人前のエンジニアになる為のブログです

SQL データの集計に関して

売上の計算をするSQLを制作していまして、特定条件で絞り込んだ顧客の初回購入から〇ヵ月間の売上を取得する という処理を制作したので、手順等を記載いたします。

まず前提として以下のようなテーブルがあるとします。

customersテーブル
     顧客名   登録日(顧客として登録された年月日)
+---+-------+-----------+
|id |name   |created    |
+---+-------+-----------+
|1  |tanaka |2017-01-01 |
|2  |yamada |2017-02-02 |
|3  |satou  |2017-03-03 |
|4  |ito    |2017-03-04 |
|5  |katou  |2017-02-05 |
+---+-------+-----------+

customer_historiesテーブル
      顧客id         注文日          購入回数         注文id      媒体id
+---+------------+----------------+------------------+---------+---------+
|id |customer_id |date_of_purchase|number_of_purchase|order_id |media_id |
+---+------------+----------------+------------------+---------+---------+
|1  | 1          |2017-01-05      | 1                |1        |1        |
|1  | 1          |2017-02-05      | 2                |2        |1        |
|1  | 1          |2017-03-05      | 3                |3        |1        |
|1  | 2          |2017-04-01      | 1                |4        |1        |
|1  | 3          |2017-05-01      | 1                |5        |1        |
|1  | 4          |2017-06-01      | 1                |6        |1        |
|1  | 5          |2017-07-01      | 1                |7        |         |
+---+------------+----------------+------------------+---------+---------+

ordersテーブル
      顧客id         注文日          金額
+---+------------+--------------+--------------+
|id |customer_id |order_date    | total_amount |
+---+------------+--------------+--------------+
|1  | 1          |2017-01-05    | 100          |
|2  | 1          |2017-02-05    | 200          |
|3  | 1          |2017-03-05    | 300          |
|4  | 2          |2017-04-01    | 100          |
|5  | 3          |2017-05-01    | 100          |
|6  | 4          |2017-06-01    | 100          |
|7  | 5          |2017-07-01    | 500          |
+---+------------+--------------+--------------+

mediasテーブル
     媒体名   
+---+--------+
|id |name    |
+---+--------+
|1  |blog    |
|2  |twitter |
+---+--------+

まず条件として2つの軸で集計いたします。初回流入媒体と登録日です。 初回流入媒体ごとに分けて更に登録月別に分けます。 登録月別に別れた顧客の初回購入から3ヵ月間の購入の売上を計算します。 以下のようなSQLになります。

select
    ch.id as '媒体ID',
    ch.name as '媒体名',
    DATE_FORMAT(ch.created , '%Y%m') as '顧客登録月',
    FORMAT(count(distinct orders.customer_id),0) AS '顧客数',
    FORMAT(sum(orders.total_amount),0) AS '総売上'
FROM
    orders
INNER JOIN
    --サブクエリで初回購入のテーブルを作ります
    (
    SELECT
        customer_histories.customer_id,
        customer_histories.date_of_purchase,
        medias.id,
        medias.name,
        customers.created
    FROM
        customer_histories
    INNER JOIN
        --登録年月日を出すためcustomersテーブルを結合します
        customers
    ON
        customers.id = customer_histories.customer_id
    INNER JOIN
        medias
    ON
        customer_histories.media_id = medias.id
    WHERE
        --初回購入の条件
        customer_histories.number_of_purchase = 1
        ) AS ch
ON
    orders.customer_id = ch.customer_id
WHERE
    --初回の注文年月から 2 MONTH つまり2ヵ月間のデータに絞り込みます
    DATE_FORMAT(orders.order_date ,'%Y%m') <= DATE_FORMAT(DATE_ADD(ch.date , INTERVAL 2 MONTH),'%Y%m')
GROUP BY
    --まず初回流入媒体ごとに分けます
    ch.id,
    --次に登録年月ごとに分けます
    DATE_FORMAT(ch.created ,'%Y%m')
ORDER BY
    --medias.idの昇順に並び替えます
    ch.id

上記のようになりまして結果は以下のようになります。

+-----------+------------+-----------+-------+--------+
|媒体ID      |媒体名      |顧客登録月 |顧客数  |総売上  |
+-----------+------------+-----------+-------+--------+
|1          | blog       |2017-01    | 1     |600     |
|1          | blog       |2017-02    | 1     |100     |
|1          | blog       |2017-03    | 2     |200     |
+-----------+------------+-----------+-------+--------+

確認すべき点は3つです。

  1. まずは初回購入の媒体ごとに分かれている

  2. 登録月ごとに分かれているので登録月が3月の customers.id 3[satou]と4[ito]の2人が3行目で合算されています。総売上も合算されています。

  3. 購入時にメディアIDのなかった customers.id 5[katou]が分析に含まれていません。

続いてWHEREの[2 MONTH]を[1 MONTH]に変えてみます。 そうすると初回購入から2ヵ月間の売上を出力します。

+-----------+------------+-----------+-------+--------+
|媒体ID      |媒体名      |顧客登録月 |顧客数  |総売上  |
+-----------+------------+-----------+-------+--------+
|1          | blog       |2017-01    | 1     |300     |
|1          | blog       |2017-02    | 1     |100     |
|1          | blog       |2017-03    | 2     |200     |
+-----------+------------+-----------+-------+--------+

細かい違いですが、1行目の総売上が300になっています。 これは2ヵ月間の分析に変更したのでcustomers.id 1[tanaka]の3月の購入が 除外されたことが原因です。

これらが特定条件で絞り込んだ顧客の初回購入から〇ヵ月間の売上を取得するSQLになります。

それでは