3

ある月から次の月までの保持を示す基本的な表を取得しようとしています。つまり、誰かが先月何かを購入し、翌月に購入した場合、それはカウントされます。

month, num_transactions, repeat_transactions, retention
2012-02, 5, 2, 40%
2012-03, 10, 3, 30%
2012-04, 15, 8, 53%

したがって、先月購入した全員が翌月に再度購入した場合、100% となります。

これまでのところ、手動​​でしか計算できません。これにより、両方の月に見られた行が得られます。

select count(*) as num_repeat_buyers from 

(select distinct
  to_char(transaction.timestamp, 'YYYY-MM') as month,
  auth_user.email
from
  auth_user,
  transaction
where
  auth_user.id = transaction.buyer_id and
  to_char(transaction.timestamp, 'YYYY-MM') = '2012-03'
) as table1,


(select distinct
  to_char(transaction.timestamp, 'YYYY-MM') as month,
  auth_user.email
from
  auth_user,
  transaction
where
  auth_user.id = transaction.buyer_id and
  to_char(transaction.timestamp, 'YYYY-MM') = '2012-04'
) as table2
where table1.email = table2.email

これは正しくありませんが、Postgres のウィンドウ機能のいくつかを使用できるように感じます。ウィンドウ関数では WHERE 句を指定できないことに注意してください。ほとんどの場合、前の行と前の行にアクセスできます。

select month, count(*) as num_transactions, count(*) over (PARTITION BY month ORDER BY month)
from 
    (select distinct
      to_char(transaction.timestamp, 'YYYY-MM') as month,
      auth_user.email
    from
      auth_user,
      transaction
    where
      auth_user.id = transaction.buyer_id
    order by
      month
    ) as transactions_by_month
group by
    month
4

2 に答える 2

6

次のテスト テーブル (提供する必要があります) が与えられた場合:

CREATE TEMP TABLE transaction (buyer_id int, tstamp timestamp);
INSERT INTO transaction VALUES 
 (1,'2012-01-03 20:00')
,(1,'2012-01-05 20:00')
,(1,'2012-01-07 20:00')  -- multiple transactions this month
,(1,'2012-02-03 20:00')  -- next month
,(1,'2012-03-05 20:00')  -- next month
,(2,'2012-01-07 20:00')
,(2,'2012-03-07 20:00')  -- not next month
,(3,'2012-01-07 20:00')  -- just once
,(4,'2012-02-07 20:00'); -- just once

auth_userは問題に関連していません。基本型を識別子として使用しないため、列名として
使用します。tstamp

ウィンドウ関数lag()を使用して、リピート購入者を特定します。簡潔にするために、1 つのクエリ レベルで集計関数とウィンドウ関数を組み合わせます。ウィンドウ関数は集約関数の後に適用されることに注意してください。

WITH t AS (
   SELECT buyer_id
         ,date_trunc('month', tstamp) AS month
         ,count(*) AS item_transactions
         ,lag(date_trunc('month', tstamp)) OVER (PARTITION BY  buyer_id
                                           ORDER BY date_trunc('month', tstamp)) 
          = date_trunc('month', tstamp) - interval '1 month'
            OR NULL AS repeat_transaction
   FROM   transaction
   WHERE  tstamp >= '2012-01-01'::date
   AND    tstamp <  '2012-05-01'::date -- time range of interest.
   GROUP  BY 1, 2
   )
SELECT month
      ,sum(item_transactions) AS num_trans
      ,count(*) AS num_buyers
      ,count(repeat_transaction) AS repeat_buyers
      ,round(
          CASE WHEN sum(item_transactions) > 0
             THEN count(repeat_transaction) / sum(item_transactions) * 100
             ELSE 0
          END, 2) AS buyer_retention
FROM   t
GROUP  BY 1
ORDER  BY 1;

結果:

  month  | num_trans | num_buyers | repeat_buyers | buyer_retention_pct
---------+-----------+------------+---------------+--------------------
 2012-01 |         5 |          3 |             0 |               0.00
 2012-02 |         2 |          2 |             1 |              50.00
 2012-03 |         2 |          2 |             1 |              50.00

取引数と購入者数の差を説明するために質問を拡張しました。

OR NULLforrepeat_transactionは に変換FALSEするためのものであるため、これらの値は次のステップでNULLカウントされません。count()

-> SQLフィドル。

于 2013-05-11T10:44:38.887 に答える
0

これはCASE、 とを使用しEXISTSて繰り返しトランザクションを取得します。

SELECT
    *,
    CASE
        WHEN num_transactions = 0
        THEN 0
        ELSE round(100.0 * repeat_transactions / num_transactions, 2)
    END AS retention
FROM
    (
        SELECT
            to_char(timestamp, 'YYYY-MM') AS month,
            count(*) AS num_transactions,
            sum(CASE
                WHEN EXISTS (
                    SELECT 1
                    FROM transaction AS t
                    JOIN auth_user AS u
                    ON t.buyer_id = u.id
                    WHERE
                        date_trunc('month', transaction.timestamp)
                            + interval '1 month'
                            = date_trunc('month', t.timestamp)
                        AND auth_user.email = u.email
                )
                THEN 1
                ELSE 0
            END) AS repeat_transactions
        FROM
            transaction
            JOIN auth_user
            ON transaction.buyer_id = auth_user.id
        GROUP BY 1
    ) AS summary
ORDER BY 1;

編集: 質問をもう一度読んだ後、マイナス 1 か月からプラス 1 か月に変更されました。私の理解では、誰かが 2012 年 2 月に何かを購入し、2012 年 3 月に再び何かを購入した場合、2012 年 2 月のトランザクションはその月の保留としてカウントされます。

于 2013-05-11T08:14:34.040 に答える