sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur man beräknar retention månad över månad med SQL

Med tanke på följande testtabell (som du borde ha tillhandahållit):

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

Tabell auth_user är inte relevant för problemet.
Använder tstamp som kolumnnamn eftersom jag inte använder bastyper som identifierare.

Jag kommer att använda fönsterfunktionen lag() för att identifiera återkommande köpare. För att hålla det kort kombinerar jag aggregat- och fönsterfunktioner på en frågenivå. Tänk på att fönsterfunktioner tillämpas efter aggregerade funktioner.

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;

Resultat:

  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

Jag utökade din fråga för att ta hänsyn till skillnaden mellan antalet transaktioner och antalet köpare.

ELLER NULL för repeat_transaction tjänar till att konvertera FALSK till NULL , så dessa värden räknas inte av count() i nästa steg.

-> SQLfiddle.



  1. PostgreSQL - Byt namn på databas

  2. Bifoga en MDF-fil utan LDF-fil

  3. 3 sätt att ersätta NULL med "N/A" i SQLite

  4. sql self-join table ta bort dubbletter av rader