Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.80) (envelope-from ) id 1WJLsx-0000IC-CO for pgsql-sql@arkaria.postgresql.org; Fri, 28 Feb 2014 11:45:47 +0000 Received: from localhost ([127.0.0.1] helo=postgresql.org) by malur.postgresql.org with smtp (Exim 4.80) (envelope-from ) id 1WJLsw-0000G7-Sq for pgsql-sql@arkaria.postgresql.org; Fri, 28 Feb 2014 11:45:46 +0000 Received: from makus.postgresql.org ([2001:4800:7903:4::125]) by malur.postgresql.org with esmtp (Exim 4.80) (envelope-from ) id 1WJLsw-0000G0-2x for pgsql-sql@postgresql.org; Fri, 28 Feb 2014 11:45:46 +0000 Received: from zimbra.isdd.sk ([91.233.248.204]) by makus.postgresql.org with esmtp (Exim 4.80) (envelope-from ) id 1WJLsf-0003YG-4V for pgsql-sql@postgresql.org; Fri, 28 Feb 2014 11:45:45 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by zimbra.isdd.sk (Postfix) with ESMTP id 4BE7EAC86A7; Fri, 28 Feb 2014 12:45:27 +0100 (CET) X-Virus-Scanned: amavisd-new at zimbra.isdd.sk Received: from zimbra.isdd.sk ([127.0.0.1]) by localhost (zimbra.isdd.sk [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 1EDpvU8MoJwY; Fri, 28 Feb 2014 12:45:26 +0100 (CET) Received: from zimbra.isdd.sk (zimbra.isdd.sk [91.233.248.204]) by zimbra.isdd.sk (Postfix) with ESMTP id D85D9AC865E; Fri, 28 Feb 2014 12:45:26 +0100 (CET) Date: Fri, 28 Feb 2014 12:45:26 +0100 (CET) From: Jan Ostrochovsky To: David Johnston Cc: pgsql-sql@postgresql.org Message-ID: <976203811.595346.1393587926835.JavaMail.root@mobiletech.sk> In-Reply-To: <1393513774376-5793882.post@n5.nabble.com> Subject: Re: how to effectively SELECT new "customers" MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_Part_595345_143802898.1393587926834" X-Originating-IP: [10.8.253.141] X-Mailer: Zimbra 7.2.6_GA_2926 (ZimbraWebClient - GC33 (Win)/7.2.6_GA_2926) X-Pg-Spam-Score: -1.9 (-) List-Archive: List-Help: List-ID: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-Mailing-List: pgsql-sql Precedence: bulk Sender: pgsql-sql-owner@postgresql.org ------=_Part_595345_143802898.1393587926834 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit ----- Original Message ----- > From: "David Johnston" > To: pgsql-sql@postgresql.org > Sent: Thursday, February 27, 2014 4:09:34 PM > Subject: Re: [SQL] how to effectively SELECT new "customers" > Jan Ostrochovsky wrote > > Hello, I am solving following task and it seems hard to me to find > > effective solution. Maybe somebody knows how to help me: We have > > table > > "purchases" and each one record is identified by "customer_id". We > > want to > > know not only how many different customers did at least one > > purchase per > > time period, grouped by time periods (easy task: "COUNT(DISTINCT > > customer_id)" with "GROUP BY period"), but also to know how many > > NEW > > customers there were. We define new customer as customer_id, which > > had > > first record in table "purchases" after 12 month of inactivity (no > > record > > in table "purchases" previous 12 months). I have found one > > solution, but > > it is very slow and ugly. I tried several other concepts, but > > without > > success. Any hint could be helpful for me. Thanks in advance! Jano > Without incorporating additional meta-data about the purchases onto > the > customer table the most basic solution would be: > SELECT DISTINCT customer_id FROM products WHERE date > (now() - '12 > months'::interval) > EXCEPT > SELECT DISTINCT customer_id FROM products WHERE date <= (now() - '12 > months'::interval) > --- > Another solution: > WHERE ... >12 AND NOT EXISTS (SELECT ... WHERE <= 12) > --- > Depending on the frequency that you need to run this query it may be > worthwhile to create a materialized view that captures the necessary > data > and then whenever a new sale is generated you simply update that view > by > changing the attributes of that single customer. At any point you can > quickly determine, using the view, which customers were active at the > time > of last purchases and which ones were dormant or non-existent. > David J. Thank you David, your alternatives seem as smart alternatives of my solution, what is based on the difference between COUNT(DISTINCT customer_id) in e.g. 13 months (in case when reporting period is 1 month over previous 12 months) and COUNT(DISTINCT customer_id) in 12 months prior to reporting period (but without the reporting period). But I would also like to incorporate other data in the output, which should seem e.g.: town, period, payment_channel_id, purchases_count, purchases_total_revenue, distinct_customer_count, distinct_NEW_customer_count BA, 201401, A, 495, 847, 103, 25 BA, 201401, B, 345, 456, 99, 21 BA, 201312, A, 554, 1021, 105, 30 ZA, 201401, A, 323, 987, 95, 23 ... there is 12-month-long time-window for new customer determination, sliding according to particular period, back to the past how to achieve this? e.g. by running your or my concept repeatedly (manually or in the higher level loop), but this is too slow... or to find more sophisticated SQL query to accomplish this in one step... any other ideas for such SQL query running once, not repeatedly (in loop) for each reporting period? (I was considering window functions, connectby, grouping sets, ..., but no success yet) materialized view could be part of that solution, when we will have the right query and uprgade from 9.0 to 9.3 (as I see it: http://www.postgresql.org/docs/9.3/static/rules-materializedviews.html)... but it should be scalable to several to tens purchases every minute thanks again for your contribution, David Jano ------=_Part_595345_143802898.1393587926834 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable <= div style=3D'font-family: times new roman,new york,times,serif; font-size: = 12pt; color: #000000'>
From: "David Johnston" <polobo@yahoo.com&g= t;
To: pgsql-sql@postgresql.org
Sent: Thursday, Februar= y 27, 2014 4:09:34 PM
Subject: Re: [SQL] how to effectively SELEC= T new "customers"

Jan Ostrochovsky wrote
> Hello, I am solving= following task and it seems hard to me to find
> effective solution.= Maybe somebody knows how to help me: We have table
> "purchases" and= each one record is identified by "customer_id". We want to
> know no= t only how many different customers did at least one purchase per
> t= ime period, grouped by time periods (easy task: "COUNT(DISTINCT
> cus= tomer_id)" with "GROUP BY period"), but also to know how many NEW
> c= ustomers there were. We define new customer as customer_id, which had
&g= t; first record in table "purchases" after 12 month of inactivity (no recor= d
> in table "purchases" previous 12 months). I have found one soluti= on, but
> it is very slow and ugly. I tried several other concepts, b= ut without
> success. Any hint could be helpful for me. Thanks in adv= ance! Jano

Without incorporating additional meta-data about the purc= hases onto the
customer table the most basic solution would be:

S= ELECT DISTINCT customer_id FROM products WHERE date > (now() - '12
mo= nths'::interval)
EXCEPT
SELECT DISTINCT customer_id FROM products WHE= RE date <=3D (now() - '12
months'::interval)

---

Anothe= r solution:
WHERE ... >12 AND NOT EXISTS (SELECT ... WHERE <=3D 12= )

---

Depending on the frequency that you need to run this qu= ery it may be
worthwhile to create a materialized view that captures the= necessary data
and then whenever a new sale is generated you simply upd= ate that view by
changing the attributes of that single customer.  = At any point you can
quickly determine, using the view, which customers = were active at the time
of last purchases and which ones were dormant or= non-existent.

David J.
Thank you David, your altern= atives seem as smart alternatives of my solution, what is based on the diff= erence between COUNT(DISTINCT customer_id) in e.g. 13 months (in case when = reporting period is 1 month over previous 12 months) and COUNT(DISTINCT cus= tomer_id) in 12 months prior to reporting period (but without the reporting= period). But I would also like to incorporate other data in the output, wh= ich should seem e.g.:

town, period, payment_channel_id, = purchases_count, purchases_total_revenue, distinct_customer_count, distinct= _NEW_customer_count
BA, 201401, A, 495, 847, 103, 25
BA= , 201401, B, 345, 456, 99, 21
BA, 201312, A, 554, 1021, 105, 30
ZA, 201401, A, 323, 987, 95, 23
...

there is 12-m= onth-long time-window for new customer determination, sliding according to = particular period, back to the past

how to achieve= this? e.g. by running your or my concept repeatedly (manually or in the hi= gher level loop), but this is too slow... or to find more sophisticated SQL= query to accomplish this in one step... any other ideas for such SQL query= running once, not repeatedly (in loop) for each reporting period? (I was c= onsidering window functions, connectby, grouping sets, ..., but no success = yet)

materialized view could be part of that solut= ion, when we will have the right query and uprgade from 9.0 to 9.3 (as I se= e it: http://www.postgresql.org/docs/9.3/static/rules-materializedview= s.html)... but it should be scalable to several to tens purchases every min= ute

thanks again for your contribution, David

Jano

------=_Part_595345_143802898.1393587926834--