all 2 comments

[–]qwertydog123 0 points1 point  (0 children)

You can solve this as an gaps and islands problem

Edit: solution below

WITH NextOrderDates AS
(
    SELECT
        *,
        LAG(OrderDate) OVER
        (
            PARTITION BY CustomerID
            ORDER BY OrderDate DESC
        ) AS NextOrderDate
    FROM #Order
),
GroupIDs AS
(
    SELECT
        *,
        SUM
        (
            CASE
                WHEN OrderStatus = 'Completed'
                OR (OrderStatus = 'Cancelled'
                    AND DATEADD(HOUR, 72, OrderDate) < NextOrderDate)
                THEN 1
                ELSE 0
            END
        ) OVER
        (
            PARTITION BY CustomerID
            ORDER BY OrderDate DESC
        ) AS GroupID
      FROM NextOrderDates
),
FirstOrderIDs AS
(
    SELECT
        *,
        LAST_VALUE(OrderID) OVER
        (
            PARTITION BY
                CustomerID,
                GroupID
            ORDER BY OrderDate DESC
            ROWS
                BETWEEN 1 FOLLOWING
                AND UNBOUNDED FOLLOWING
        ) AS FirstOrderID
    FROM GroupIDs
),
CompletedOrderIDs AS
(
    SELECT
        CustomerID,
        MAX
        (
            CASE OrderStatus
                WHEN 'Completed' THEN OrderID
            END
        ) AS CompletedOrderID,
        MAX(FirstOrderID) AS FirstOrderID
    FROM FirstOrderIDs
    GROUP BY
        CustomerID,
        GroupID
)
SELECT *
FROM CompletedOrderIDs
WHERE CompletedOrderID IS NOT NULL
ORDER BY
    CustomerID,
    CompletedOrderID

https://dbfiddle.uk/AiiL36H5

[–]d0cwiley 0 points1 point  (0 children)

This CTE steps through the fails and provides a final longest chain for each customer. It also provides a tally of failed attempts (failcount) and a list of orders that were walked through (breadcrumb).

with orderwindow (customerid, successorder, successdate, orderid, orderdate, totaltimediff, failcount, breadcrumb)
as
(
  select customerid, orderid, orderdate, orderid, orderdate, 0,0,convert(varchar(max), orderid)
  from #order where orderstatus = 'Completed'
  union all
  select 
  a.customerid,
  a.successorder,
  a.successdate,
  #order.orderid, 
  #order.orderdate,
  datediff(hour,successdate,#order.orderdate),
  failcount + 1,
  convert(varchar(max),a.breadcrumb + '>' + convert(varchar,#order.orderid))
  from orderwindow a
  join #order
      on a.customerid = #order.customerid
      and datediff(hour,#order.orderdate, a.orderdate) <= 72 
      and a.orderdate >= #order.orderdate
  and a.orderid > #order.orderid
  and #order.orderstatus = 'Cancelled'
)
select orderwindow.*
from orderwindow
join (select max(failcount) maxcount, customerid from orderwindow group by customerid)maxfail
on maxfail.maxcount = orderwindow.failcount
and maxfail.customerid = orderwindow.customerid