0

Lets say I have a table of purchases that looks like this:

Purchases
---------
Item_ID
Purchase_Date
Customer_ID

How would I be able to obtain the set of purchases, starting from the first purchase, for each customer that are at least X days after the last purcahse? For example, if we have the data below, and x=10:

Item_ID    PurchaseDate    Customer_ID    
123        07/29/23        1000
123        08/04/23        1000
123        08/16/23        1000
563        07/03/23        7785
563        07/05/23        7785
788        08/17/23        2489

The query should return:

Item_ID    PurchaseDate    Customer_ID    
123        07/29/23        1000
123        08/11/23        1000
563        07/03/23        7785
788        08/17/23        2489

So, for customer 1000, the first purchase counts, because its a new purchase. The second purchase is less than 10 days from the last purchase so it's discarded. The third purchase for this customer counts because it is more than or equal to 10 days after the last purchase. For customer 7785, only the first counts because the second purcahse is less than 10 days after the last purcahse, and finally for customer 2489, it only has one new purchase so that just counts as the new purchase.(note the first purchase always counts)

I was thinking along the lines of using the lag function

SELECT
    t.Item_ID,
    t.PurchaseDate,
    t.Customer_ID
FROM (
    SELECT
        p.Item_ID,
        p.PurchaseDate,
        p.Customer_ID,        
        LAG OVER(PARTITION BY Customer_ID ORDER BY PurchaseDate) next_purchase
        ROW_NUMBER() OVER(PARTITION BY Customer_ID ORDER BY PurchaseDate) rownum


        
    FROM
        PurchaseTable p
) t
WHERE
    DATEDIFF(DAY, t.PurchaseDate, t.next) >= 10) or rownum=1
       

EDIT: Apologies, I had the description incorrect. I changed the question and example to the correct details.

1 Answer 1

0

I have taken your code and polished it a bit - according to your description, it gives results as requested:

   CREATE TABLE Purchases (
Item_ID int, 
purchase_date datetime, 
customer_id int
);

INSERT INTO Purchases
VALUES 
(123,'2023-07-29',1000),
(123,'2023-08-04',1000),
(123,'2023-08-16',1000),
(563,'2023-07-03',7785),
(563,'2023-07-05',7785),
(788,'2023-08-17',2489)

DECLARE @threshold int = -10;   
SELECT
    t.Item_ID,
    t.purchase_date,
    t.Customer_ID
FROM (
    SELECT
        p.Item_ID,
        p.purchase_date,
        p.Customer_ID,        
        LAG(purchase_date) OVER(PARTITION BY Customer_ID ORDER BY purchase_date) next_purchase,
        ROW_NUMBER() OVER(PARTITION BY Customer_ID ORDER BY purchase_date) rownum,
        DATEDIFF(DAY,purchase_date,LAG(purchase_date) OVER(PARTITION BY Customer_ID ORDER BY purchase_date) ) AS purchases_difference
      
    FROM
        Purchases p
) t
WHERE
    (purchases_difference IS NULL OR purchases_difference < @threshold) /* or rownum=1 */
       

The biggest difference to your code is, that LAG gives you negative value (it checks the previous row and subtracts later date from an earlier date - hence negative value. Therefore, I have declared @threshold as -10 (days) and showing everything that's difference -10 days or more (i.e. -11, -12, ...). I have also deliberately commented out the rownum = 1, because that's redundant to purchases_difference IS NULL (it'll be null for every first (or only) row in the group - hence it qualifies the row to be shown).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.