sql >> Database >  >> RDS >> PostgreSQL

Hoe de retentie maand na maand te berekenen met behulp van SQL

Gezien de volgende testtabel (die u had moeten verstrekken):

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

Tabel auth_user is niet relevant voor het probleem.
Gebruik tstamp als kolomnaam aangezien ik geen basistypes als identifiers gebruik.

Ik ga de vensterfunctie gebruiken lag() om herhaalde kopers te identificeren. Om het kort te houden combineer ik aggregatie- en vensterfuncties in één zoekniveau. Houd er rekening mee dat vensterfuncties na . worden toegepast geaggregeerde functies.

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;

Resultaat:

  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

Ik heb uw vraag uitgebreid om het verschil tussen het aantal transacties en het aantal kopers op te lossen.

De OR NULL voor repeat_transaction dient om FALSE te converteren naar NULL , dus die waarden worden niet geteld door count() in de volgende stap.

-> SQLfiddle.



  1. PHP MySQL-foutafhandeling

  2. Beste aanpak om tijdgedeelte van datetime in SQL Server te verwijderen

  3. Het aanroepen van DATE_FORMAT() in MySQL vanuit Django mislukt

  4. Hoe voer ik onbewerkte SQL uit in een django-migratie?