简体   繁体   中英

SQL - Find customers who have not ordered in the last year and what they ordered

I am able to find the customers who have not ordered in the last year by doing this:

SELECT O.CustID, MAX(O.ORDERDATE) AS LastOrder FROM Orders O
WHERE LastOrder <= DATEADD(year,-1,GETDATE())
GROUP BY O.CustID

I would like to join a second table (OrderDetails) that contains the order specifics on the field called OrderID.

There is only one item per order. (my data isn't actually customers and orders - but the analogy works for what I am doing).

When I add this OrderID field into the query, my results multiply. This is happening because while when I am grouping, I am grouping by OrderID and CustID, which would pull each specific OrderID.

My question is how would I pull just the last OrderID from the OrderDetails table where the orderID for that customer is over 1 year old.

This is what I have so far

SELECT OD.OrderID, O.CustID, MAX(O.ORDERDATE) AS LastOrder 
FROM Orders O
INNER JOIN OrderDetails OD
ON O.OrderID = OD.OrderID
WHERE LastOrder <= DATEADD(year,-1,GETDATE())
GROUP BY OD.OrderID, O.CustID
 

Using:

WITH cte AS (
  SELECT O.*
  FROM Orders O
  INNER JOIN OrderDetails OD
    ON O.OrderID = OD.OrderID
  QUALIFY MAX(O.OrderDate) OVER(PARTITION BY O.CustId) <= DATEADD(year,-1,CURRENT_DATE())
)
SELECT *
FROM cte
QUALIFY ROW_NUMBER() OVER(PARTITION BY CustId ORDER BY OrderDate DESC) = 1

So almost completely a cut'n'pase of Lukasz answer BUT, the two QUALIFY filters can be merged:

WITH orders(cust_id, order_date, order_id) AS (
    SELECT column1
        ,to_date(column2,'yyyy-mm-dd')
        ,column3
    FROM VALUES
        (1,'2022-01-01',1),
        (1,'2021-01-01',2),
        (2,'2021-01-01',3),
        (3,'2021-01-01',4)
), order_details(order_id, details) AS (
    SELECT *
    FROM VALUES
        (1,'detail 1'),
        (2,'detail 2'),
        (3,'detail 3'),
        (4,'detail 4')
)
SELECT o.cust_id
    ,o.order_date as last_order_date
    ,od.details
FROM orders as o
JOIN order_details as od ON o.order_id = od.order_id
QUALIFY max(o.order_date) over(partition by o.cust_id) <= dateadd(year, -1, current_date) AND
   ROW_NUMBER() over (partition by o.cust_id ORDER BY o.order_date) = 1
ORDER BY 1;

BUT I would tend to do the filtering first (as ether a sub-select OR CTE) and then join to order_details as the details are not needed, thus you will make it the most obvious to the SQL compiler (which should see the JOIN can be done after)

WITH orders(cust_id, order_date, order_id) AS (
    SELECT column1
        ,to_date(column2,'yyyy-mm-dd')
        ,column3
    FROM VALUES
        (1,'2022-01-01',1),
        (1,'2021-01-01',2),
        (2,'2021-01-01',3),
        (3,'2021-01-01',4)
), order_details(order_id, details) AS (
    SELECT *
    FROM VALUES
        (1,'detail 1'),
        (2,'detail 2'),
        (3,'detail 3'),
        (4,'detail 4')
), stale_customers AS (
    SELECT *
    FROM orders AS o
    QUALIFY max(o.order_date) over(partition by o.cust_id) <= dateadd(year, -1, current_date) AND
        ROW_NUMBER() over (partition by o.cust_id ORDER BY o.order_date) = 1
)
SELECT o.cust_id
    ,o.order_date as last_order_date
    ,od.details
FROM stale_customers as o
JOIN order_details as od ON o.order_id = od.order_id
ORDER BY 1;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM