PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come calcolare la fidelizzazione mese dopo mese utilizzando SQL

Data la seguente tabella di test (che avresti dovuto fornire):

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

Tabella auth_user non è rilevante per il problema.
Utilizzo di tstamp come nome di colonna poiché non utilizzo i tipi di base come identificatori.

Userò la funzione finestra lag() per identificare gli acquirenti ripetuti. Per farla breve, combino le funzioni di aggregazione e finestra in un unico livello di query. Tieni presente che le funzioni della finestra vengono applicate dopo funzioni aggregate.

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;

Risultato:

  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

Ho esteso la tua domanda per fornire la differenza tra il numero di transazioni e il numero di acquirenti.

Il OR NULL per repeat_transaction serve per convertire FALSE a NULL , quindi quei valori non vengono conteggiati da count() nel passaggio successivo.

-> SQLfiddle.