I have a query which is working that finds customers who have made purchases on 10+ more consecutive days. I am trying to modify the query to use DENSE_RANK() to show the greatest amount of consecutive purchases (>= 10 days) for each customer.
Unfortunately, I'm running into some syntax errors that I'm unable to resolve and would appreciate a bit of help.
Below is my test setup, test case, what I have so far and expected result. Any help would be greatly appreciated. If there is better way to achieve my results instead of with match_recognize/rank I'm certainly open to any input. Thanks in advance to all who respond.
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'DD-MON-YYYY';
CREATE TABLE customers
(CUSTOMER_ID, FIRST_NAME, LAST_NAME) AS
SELECT 1, 'Ann', 'Aaron' FROM DUAL UNION ALL
SELECT 2, 'Jane', 'Smith' FROM DUAL UNION ALL
SELECT 3, 'Bonnie', 'Winterbottom' FROM DUAL UNION ALL
SELECT 4, 'Sandy', 'Herring' FROM DUAL UNION ALL
SELECT 5, 'Roz', 'Doyle' FROM DUAL;
create table purchases(
ORDER_ID NUMBER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
customer_id number,
PRODUCT_ID NUMBER,
QUANTITY NUMBER,
purchase_date timestamp
);
insert into purchases (customer_id, product_id, quantity, purchase_date)
select 2 customer_id, 102 product_id, 2 quantity,
TIMESTAMP '2024-04-03 00:00:00' + INTERVAL '18' HOUR + ((LEVEL-1) * INTERVAL '1 00:00:01' DAY TO SECOND) * -1 + ((LEVEL-1) * interval '0.007125' second)
as purchase_date
from dual
connect by level <= 15 UNION all
select 1, 101, 1,
DATE '2024-03-08' + INTERVAL '14' HOUR + ((LEVEL-1) * INTERVAL '1 00:00:00' DAY TO SECOND) * -1
from dual
connect by level <= 5 UNION ALL
select 3, 103, 3,
DATE '2024-02-08' + INTERVAL '15' HOUR + ((LEVEL-1) * INTERVAL '0 23:59:59' DAY TO SECOND) * -1
from dual
connect by level <= 5
UNION all
select 2, 102,1, date '2023-07-29' + level * interval '1' day from dual
connect by level <= 12
union all
select 2, 103,1, date '2023-08-29' + level * interval '1' day from dual
connect by level <= 15
union all
select 2, 104,1, date '2023-11-11' + level * interval '1' day from dual
connect by level <= 9
union all
select 4, 103,(3*LEVEL), TIMESTAMP '2023-06-01 05:18:03' + numtodsinterval ( (LEVEL -1) * 1, 'day' ) + numtodsinterval ( LEVEL * 37, 'minute' ) + numtodsinterval ( LEVEL * 3, 'second' ) FROM dual
CONNECT BY LEVEL <= 4 UNION ALL
SELECT 3, 102, 4,TIMESTAMP '2022-12-22 21:44:35' + NUMTODSINTERVAL ( LEVEL * 3, 'DAY') FROM dual
CONNECT BY LEVEL <= 13 UNION ALL
select 1, 104, (2 * LEVEL), date '2023-07-02' + level * interval '1 15:13' day to minute from dual
connect by level <= 7
union all
select 1, 101,3, date '2023-03-29' + level * interval '2' day from dual
connect by level <= 12
union all
select 2, 101,2, date '2023-01-15' + level * interval '8' hour from dual
connect by level <= 15
union all
select 2, 102,2,date '2023-04-13' + level * interval '1 1' day to hour from dual
connect by level <= 11
union all
select 3, 101,2, date '2023-02-01' + level * interval '1 05:03' day to minute from dual
connect by level <= 10
union all
select 3, 101,1, date '2023-04-22' + level * interval '23' hour from dual
connect by level <= 23
union all
select 3, 100,1, date '2022-03-01' + level * interval '1 00:23:05' day to second from dual
connect by level <= 15
union all
select 3, 101,1, date '2022-03-01' + level * interval '1 00:23:05' day to second from dual
connect by level <= 15
union all
select 4, 102,1, date '2023-01-01' + level * interval '5' hour from dual
connect by level <= 60;
/* modify working query */
select m.customer_id,
c.first_name,
c.last_name,
m.first_date,
m.last_date,
trunc(m.last_date) - trunc(m.first_date) + 1 as consecutive_days
FROM purchases pur match_recognize
(
partition by customer_id
order by purchase_date
measures
first(purchase_date) as first_date,
last(purchase_date) as last_date
one row per match
pattern(start_date P{9,})
define P as
purchase_date >= prev(trunc(purchase_date)) + interval '1' day
and purchase_date < prev(trunc(purchase_date)) + interval '2' day
) m
LEFT OUTER JOIN customers c ON c.customer_id = m.customer_id;
/* expected result */
CUSTOMER_ID FIRST_NAME LAST_NAME FIRST_DATE LAST_DATE CONSECUTIVE_DAYS
2 JANE SMITH 30-AUG-2023 13-SEP-2023 15
2 JANE SMITH 20-MAR-2024 03-APR-2024 15
3 BONNIE WINTERBOTTOM 22-APR-2023 14-MAY-2023 23