Sum of all values except the first - sql

I have the following three tables:
Customers:
Cust_ID,
Cust_Name
Products:
Prod_ID,
Prod_Price
Orders:
Order_ID,
Cust_ID,
Prod_ID,
Quantity,
Order_Date
How do I display each costumer and how much they spent excluding their very first purchase?
[A] - I can get the total by multiplying Products.Prod_Price and Orders.Quantity, then GROUP by Cust_ID
[B] - I also can get the first purchase by using TOP 1 on Order_Date for each customer.
But I couldnt figure out how to produce [A]-[B] in one query.
Any help will be greatly appreciated.

For SQL-Server 2005, 2008 and 2008R2:
; WITH cte AS
( SELECT
c.Cust_ID, c.Cust_Name,
Amount = o.Quantity * p.Prod_Price,
Rn = ROW_NUMBER() OVER (PARTITION BY c.Cust_ID
ORDER BY o.Order_Date)
FROM
Customers AS c
JOIN
Orders AS o ON o.Cust_ID = c.Cust_ID
JOIN
Products AS p ON p.Prod_ID = o.Prod_ID
)
SELECT
Cust_ID, Cust_Name,
AmountSpent = SUM(Amount)
FROM
cte
WHERE
Rn >= 2
GROUP BY
Cust_ID, Cust_Name ;
For SQL-Server 2012, using the FIRST_VALUE() analytic function:
SELECT DISTINCT
c.Cust_ID, c.Cust_Name,
AmountSpent = SUM(o.Quantity * p.Prod_Price)
OVER (PARTITION BY c.Cust_ID)
- FIRST_VALUE(o.Quantity * p.Prod_Price)
OVER (PARTITION BY c.Cust_ID
ORDER BY o.Order_Date)
FROM
Customers AS c
JOIN
Orders AS o ON o.Cust_ID = c.Cust_ID
JOIN
Products AS p ON p.Prod_ID = o.Prod_ID ;
Another way (that works in 2012 only) using OFFSET FETCH and CROSS APPLY:
SELECT
c.Cust_ID, c.Cust_Name,
AmountSpent = SUM(x.Quantity * x.Prod_Price)
FROM
Customers AS c
CROSS APPLY
( SELECT
o.Quantity, p.Prod_Price
FROM
Orders AS o
JOIN
Products AS p ON p.Prod_ID = o.Prod_ID
WHERE
o.Cust_ID = c.Cust_ID
ORDER BY
o.Order_Date
OFFSET
1 ROW
-- FETCH NEXT -- not needed,
-- 20000000000 ROWS ONLY -- can be removed
) AS x
GROUP BY
c.Cust_ID, c.Cust_Name ;
Tested at SQL-Fiddle
Note that the second solution returns also the customers with only one order (with the Amount as 0) while the other two solutions do not return those customers.

Which version of SQL? If 2012 you might be able to do something interesting with OFFSET 1, but I'd have to ponder much more how that works with grouping.
EDIT: Adding a 2012 specific solution inspired by #ypercube
I wanted to be able to use OFFSET 1 within the WINDOW to it al in one step, but the syntax I want isn't valid:
SUM(o.Quantity * p.Prod_Price) OVER (PARTITION BY c.Cust_ID
ORDER BY o.Order_Date
OFFSET 1)
Instead I can specify the row boxing, but have to filter the result set to the correct set. The query plan is different from #ypercube's, but the both show 50% when run together. They each run twice as as fast as my original answer below.
WITH cte AS (
SELECT c.Cust_ID
,c.Cust_Name
,SUM(o.Quantity * p.Prod_Price) OVER(PARTITION BY c.Cust_ID
ORDER BY o.Order_ID
ROWS BETWEEN 1 FOLLOWING
AND UNBOUNDED FOLLOWING) AmountSpent
,rn = ROW_NUMBER() OVER(PARTITION BY c.Cust_ID ORDER BY o.Order_ID)
FROM Customers AS c
INNER JOIN
Orders AS o ON o.Cust_ID = c.Cust_ID
INNER JOIN
Products AS p ON p.Prod_ID = o.Prod_ID
)
SELECT Cust_ID
,Cust_Name
,ISNULL(AmountSpent ,0) AmountSpent
FROM cte WHERE rn=1
My more general solution is similar to peter.petrov's, but his didn't work "out of the box" on my sample data. That might be an issue with my sample data or not. Differences include use of CTE and a NOT EXISTS with a correlated subquery.
CREATE TABLE Customers (Cust_ID INT, Cust_Name VARCHAR(10))
CREATE TABLE Products (Prod_ID INT, Prod_Price MONEY)
CREATE TABLE Orders (Order_ID INT, Cust_ID INT, Prod_ID INT, Quantity INT, Order_Date DATE)
INSERT INTO Customers SELECT 1 ,'Able'
UNION SELECT 2, 'Bob'
UNION SELECT 3, 'Charlie'
INSERT INTO Products SELECT 1, 10.0
INSERT INTO Orders SELECT 1, 1, 1, 1, GetDate()
UNION SELECT 2, 1, 1, 1, GetDate()
UNION SELECT 3, 1, 1, 1, GetDate()
UNION SELECT 4, 2, 1, 1, GetDate()
UNION SELECT 5, 2, 1, 1, GetDate()
UNION SELECT 6, 3, 1, 1, GetDate()
;WITH CustomersFirstOrder AS (
SELECT Cust_ID
,MIN(Order_ID) Order_ID
FROM Orders
GROUP BY Cust_ID
)
SELECT c.Cust_ID
,c.Cust_Name
,ISNULL(SUM(Quantity * Prod_Price),0) CustomerOrderTotalAfterInitialPurchase
FROM Customers c
LEFT JOIN (
SELECT Cust_ID
,Quantity
,Prod_Price
FROM Orders o
INNER JOIN
Products p ON o.Prod_ID = p.Prod_ID
WHERE NOT EXISTS (SELECT 1 FROM CustomersFirstOrder a WHERE a.Order_ID=o.Order_ID)
) b ON c.Cust_ID = b.Cust_ID
GROUP BY c.Cust_ID
,c.Cust_Name
DROP TABLE Customers
DROP TABLE Products
DROP TABLE Orders

Try this. It should do it.
SELECT c1.cust_name ,
c1.cust_id ,
SUM(p1.Prod_Price)
FROM orders o1
JOIN products p1 ON o1.prod_id = p1.prod_id
JOIN customers c1 ON o1.cust_id = c1.cust_id
LEFT JOIN ( SELECT o2.cust_id ,
MIN(o2.Order_Date) AS Order_Date
FROM orders o2
GROUP BY o2.cust_id
) t ON o1.cust_id = t.cust_id
AND o1.Order_Date = t.Order_Date
WHERE t.Order_Date IS NULL
GROUP BY c1.cust_name ,
c1.cust_id

You have to number orders by Customer and then you can have the amount for the first order and next orders with a CTE and ROW_NUMBER() like this:
; WITH NumberedOrders
AS ( SELECT Customers.Cust_Id ,
Customers.Cust_Name ,
ROW_NUMBER() OVER ( ORDER BY Customers.Cust_id ) AS Order_Number ,
Orders.Order_Date ,
Products.Prod_price * Orders.Quantity AS Amount
FROM Orders
INNER JOIN Customers ON Orders.Cust_Id = Customers.Cust_Id
INNER JOIN Products ON Orders.Prod_Id = Products.Prod_Id
)
SELECT Cust_Id ,
SUM(CASE WHEN Order_Number = 1 THEN Amount
ELSE 0
END) AS A_First_Order ,
SUM(CASE WHEN Order_Number = 1 THEN 0
ELSE Amount
END) AS B_Other_orders ,
SUM(Amount) AS C_All_orders
FROM NumberedOrders
GROUP BY Cust_Id
ORDER BY Cust_Id

Related

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;

Multiple SQL filter on same column

How do I display the customer_id of customers who bought products A and B, but didn’t buy product C, ordered by ascending customer ID.
I tried the below code, but does not give me any result.
select customer_id, product_name from orders where customer_id = 'A' and 'product_name '= 'B'
select customer_id from orders where product_name = 'A'
intersect
select customer_id from orders where product_name = 'B'
except
select customer_id from orders where product_name = 'C'
You can use analytical function as follows:
Select * from
(select customer_id, product_name ,
Count(distinct case when product_name in ('A','B') then product_name end)
Over (partition by customer_id) as cntab ,
Count(case when product_name = 'C' then product_name end)
Over (partition by customer_id) as cntc
from orders t) t
Where cntab = 2 and cntc = 0;
One method use exists and not exists:
select o.*
from orders o
where exists (select 1
from orders o2
where o2.customer_id = o.customer_id and o2.product_name = 'A'
) and
exists (select 1
from orders o2
where o2.customer_id = o.customer_id and o2.product_name = 'B'
) and
not exists (select 1
from orders o2
where o2.customer_id = o.customer_id and o2.product_name = 'C'
)
order by customer_id;
To me, this query reads well ...
SELECT customer_id
FROM (
SELECT TableA.customer_id
FROM (
SELECT customer_id
FROM orders
WHERE product_name = 'A'
) AS TableA
INNER JOIN (
SELECT customer_id
FROM orders
WHERE product_name = 'B'
) AS TableB
ON TableA.customer_id = TableB.customer_id
) AS TableX
WHERE customer_id NOT IN (SELECT customer_id FROM orders WHERE product_name = 'C')
Explanation. Get a list of customer ids that bought products A and B with self inner join. Then, pare that list down by removing any rows where those customers bought product C.

Divide results in two columns depending on the input values? SQL Server

I am using the Nortwind database with SQL Server 2014, I try to make a query to divide the results of the orders in two different years, The format that I want in my query is
category |anio one | anio two
where the years may vary , What I try so far is
SELECT ca.CategoryName , YEAR(o.OrderDate), SUM(ot.UnitPrice*ot.Quantity) as total
FROM Orders o
INNER JOIN [Order Details] ot ON O.OrderID = ot.OrderID
INNER JOIN Products pro ON ot.ProductID = pro.ProductID
INNER JOIN Categories ca ON pro.CategoryID = ca.CategoryID
GROUP BY ca.CategoryName,YEAR(o.OrderDate)
ORDER BY ca.CategoryName;
This gives me the totals of each category for a different year, 1996-1997-1998 in column YEAR(o.OrderDate)
I want to get for example
CategoryName | 1996 | 1997
Beverages |53879,20 | 110424,00
Condiments |19458,30 | 59679,00
....
Use "conditional aggregates".
SELECT
ca.CategoryName
, SUM(case when year(o.OrderDate) = 1996 then ot.UnitPrice * ot.Quantity end) AS total_1996
, SUM(case when year(o.OrderDate) = 1997 then ot.UnitPrice * ot.Quantity end) AS total_1997
FROM Orders o
INNER JOIN [Order Details] ot ON o.OrderID = ot.OrderID
INNER JOIN Products pro ON ot.ProductID = pro.ProductID
INNER JOIN Categories ca ON pro.CategoryID = ca.CategoryID
where o.OrderDate >= '19960101' and o.OrderDate < '19980101'
GROUP BY
ca.CategoryName
ORDER BY
ca.CategoryName
Basically that means use a case expression inside the aggregate function.
I case you are wondering why I have not used "between in the where clause: see
Bad habits to kick : mis-handling date / range queries
You can use PIVOT to get your desired Output
BEGIN TRAN
CREATE TABLE #Temp(CategoryName NVARCHAR(50),[Year]INT,TOTAL DECIMAL(15,2))
INSERT INTO #Temp
SELECT ca.CategoryName , YEAR(o.OrderDate), SUM(ot.UnitPrice*ot.Quantity) as total
FROM Orders o
INNER JOIN [Order Details] ot ON O.OrderID = ot.OrderID
INNER JOIN Products pro ON ot.ProductID = pro.ProductID
INNER JOIN Categories ca ON pro.CategoryID = ca.CategoryID
GROUP BY ca.CategoryName,YEAR(o.OrderDate)
ORDER BY ca.CategoryName;
SELECT * FROM #Temp
GO
select *
from
(
select CategoryName, [Year], TOTAL
from #Temp
) src
pivot
(
sum(TOTAL)
for YEAR in ([1996], [1997]
)) piv;
ROLLBACK TRAN
you can use pivot to get the desired output
CREATE TABLE #TEMP
(
Category VARCHAR(200),
YEAR1 NUMERIC,
Total MONEY
)
INSERT INTO #TEMP
SELECT 'beverages', 1996, 500
union
SELECT 'beverages', 1997, 750
union
SELECT 'Condiments', 1997, 1000
union
SELECT 'Condiments', 1996, 800
SELECT *
FROM
(
SELECT Category,YEAR1, Total FROM #TEMP
) AS SourceTable
PIVOT
(
AVG(Total) FOR YEAR1 IN ( [1996], [1997])
) AS PivotTable;

Join two tables on one without mutyplying rows per record

Let say we have 3 tables named TRANSACTIONS, ORDERS, PAYMENTS all of them having TRANSACTION_ID.
This is the regular output I get when joining transaction that has 5 orders and 3 payments:
transaction_id, order_id, payment_id
----------
1, 20, 35
1, 20, 36
1, 20, 37
1, 21, 35
1, 21, 36
1, 21, 37
....
What I should get is:
transaction_id, order_id, payment_id
----------
1, 20, 35
1, 21, 36
1, 22, 37
1, 23, null
1, 24, null
If there are more payments than orders, it should have NULL in the order_id column.
Basically I need to have number of rows per transaction_id equal to the bigger number of count of orders/payments (in this example 5 > 3 so 5).
Have in mind that each of these tables have couple of million records.
EDIT:
By the request in the comment, above query is simple join
SELECT t.transaction_id, o.order_id, p.payment_id
FROM TRANSACTION t
LEFT JOIN ORDERS o on o.transaction_id = t.transaction_id
LEFT JOIN PAYMENTS p on p.transaction_id = o.transaction_id
EDIT 2:
I cannot disclose full table schemes, I only wrote columns essential for the query to work. In reality every of those tables has 20+ columns, and the query should return a combined total of around 20 columns.
Again, TRANSACTIONS has over 100m records, and both ORDERS and PAYMENTS have 150m+ records of which we need around 100k records to be returned.
You should union both results and check rows for it like below :
select transaction_id, sum(order_id) as order_id, sum(payment_id) as payment_id
from
(
SELECT t.transaction_id,
ROW_NUMBER() OVER (PARTITION BY t.transaction_id ORDER BY order_id) RowNo,
o.order_id,
null as payment_id
FROM TRANSACTIONS t
LEFT JOIN ORDERS o on o.transaction_id = t.transaction_id
union
SELECT t.transaction_id,
ROW_NUMBER() OVER (PARTITION BY t.transaction_id ORDER BY payment_id) RowNo,
null as order_id,
p.payment_id
FROM TRANSACTIONS t
LEFT JOIN Payments p on p.transaction_id = t.transaction_id
) tt
group by transaction_id, RowNo
SQL Fiddle Demo : http://sqlfiddle.com/#!3/e991d/21
UPDATE :
Please try it with JOIN instead of UNION like below :
SELECT t1.transaction_id, t1.order_id, t2.payment_id
from
(
SELECT t.transaction_id,
ROW_NUMBER() OVER (PARTITION BY t.transaction_id ORDER BY order_id) RowNo,
o.order_id
FROM TRANSACTIONS t
LEFT JOIN ORDERS o on o.transaction_id = t.transaction_id
) t1
full join
(
SELECT t.transaction_id,
ROW_NUMBER() OVER (PARTITION BY t.transaction_id ORDER BY p.payment_id) RowNo,
p.payment_id
FROM TRANSACTIONS t
LEFT JOIN Payments p on p.transaction_id = t.transaction_id
) t2
on t1.transaction_id = t2.transaction_id and t1.RowNo = t2.RowNo
SQL Fiddle Demo : http://sqlfiddle.com/#!3/e991d/20
In this case you should add one extra RowNumber column (using ROW_NUMBER() OVER) to the Orders and Payments tables and then join them with this column.
SQLFiddle demo
select tr.transaction_id,
Orders.order_id,
Payments.payment_id
from TRANSACTIONS tr
LEFT JOIN
(
select transaction_id,order_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY order_id) as rn
FROM ORDERS
) Orders on tr.transaction_id=Orders.transaction_id
LEFT JOIN
(
select transaction_id,payment_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY payment_id) as rn
FROM PAYMENTS
) Payments on (tr.transaction_id=Payments.transaction_id)
AND (Orders.rn=Payments.rn)
UNION
select tr.transaction_id,
Orders.order_id,
Payments.payment_id
from TRANSACTIONS tr
LEFT JOIN
(
select transaction_id,payment_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY payment_id) as rn
FROM PAYMENTS
) Payments on (tr.transaction_id=Payments.transaction_id)
LEFT JOIN
(
select transaction_id,order_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY order_id) as rn
FROM ORDERS
) Orders on tr.transaction_id=Orders.transaction_id
AND (Orders.rn=Payments.rn)
Another way is here without union. In this case we need to generate sequence 1,2,3,4.... and then JOIN both tables joining also with RowNumber to this sequence. In this example we generate sequence from 1 to 1000 (CONNECT BY LEVEL <= 1000). If you don't know what is the maximum rows count possible then you can generate sequence using select COUNT() ... from both tables as a maximum number for sequence generator.
SQLFiddle demo
select tr.transaction_id,
Orders.order_id,
Payments.payment_id
from TRANSACTIONS tr
CROSS JOIN
(SELECT LEVEL as rn
FROM dual
CONNECT BY LEVEL <= 1000
) Cnt
LEFT JOIN
(
select transaction_id,order_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY order_id) as rn
FROM ORDERS
) Orders on (tr.transaction_id=Orders.transaction_id)
AND
(cnt.rn=Orders.rn )
LEFT JOIN
(
select transaction_id,payment_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY payment_id) as rn
FROM PAYMENTS
) Payments on (tr.transaction_id=Payments.transaction_id)
AND
(cnt.rn=Payments.rn)
WHERE Payments.payment_id IS NOT NULL or
Orders.Order_id IS NOT NULL
order by tr.transaction_id,cnt.rn

Last order item in Oracle SQL

I need to list columns from customer table, the date from first order and all data from last one, in a 1:N relationship between customer and order tables. I'm using Oracle 10g.
How the best way to do that?
TABLE CUSTOMER
---------------
id NUMBER
name VARCHAR2(200)
subscribe_date DATE
TABLE ORDER
---------------
id NUMBER
id_order NUMBER
purchase_date DATE
purchase_value NUMBER
Here is one way of doing it, using the row_number function, one join, and on aggregation:
select c.*,
min(o.purchase_date) as FirstPurchaseDate,
min(case when seqnum = 1 then o.id_order end) as Last_IdOrder,
min(case when seqnum = 1 then o.purchase_date end) as Last_PurchaseDate,
min(case when seqnum = 1 then o.purchase_value end) as Last_PurchaseValue
from Customer c join
(select o.*,
row_number() over (partition by o.id order by purchase_date desc) as seqnum
from orders o
) o
on c.customer_id = o.order_id
group by c.customer_id, c.name, c.subscribe_date
It's not obvious how to join the customer table to the orders table (order is a reserved word in Oracle so your table can't be named order). If we assume that the id_order in orders joins to the id in customer
SELECT c.id customer_id,
c.name name,
c.subscribe_date,
o.first_purchase_date,
o.id last_order_id,
o.purchase_date last_order_purchase_date,
o.purchase_value last_order_purchase_value
FROM customer c
JOIN (SELECT o.*,
min(o.purchase_date) over (partition by id_order) first_purchase_date,
rank() over (partition by id_order order by purchase_date desc) rnk
FROM orders o) o ON (c.id = o.id_order)
WHERE rnk = 1
I'm confused by your field names, but I'm going to assume that ORDER.id is the id in the CUSTOMER table.
The earliest order date is easy.
select CUSTOMER.*, min(ORDER.purchase_date)
from CUSTOMER
inner join ORDER on CUSTOMER.id = ORDER.id
group by CUSTOMER.*
To get the last order data, join this to the ORDER table again.
select CUSTOMER.*, min(ORD_FIRST.purchase_date), ORD_LAST.*
from CUSTOMER
inner join ORDER ORD_FIRST on CUSTOMER.id = ORD_FIRST.id
inner join ORDER ORD_LAST on CUSTOMER.id = ORD_LAST.id
group by CUSTOMER.*, ORD_LAST.*
having ORD_LAST.purchase_date = max(ORD_FIRST.purchase_date)
Maybe something like this assuming the ID field in the Order table is actually the Customer ID:
SELECT C.*, O1.*, O2.purchase_Date as FirstPurchaseDate
FROM Customer C
LEFT JOIN
(
SELECT Max(purchase_date) as pdate, id
FROM Orders
GROUP BY id
) MaxPurchaseOrder
ON C.Id = MaxPurchaseOrder.Id
LEFT JOIN Orders O1
ON MaxPurchaseOrder.pdate = O1.purchase_date
AND MaxPurchaseOrder.id = O1.id
LEFT JOIN
(
SELECT Min(purchase_date) as pdate, id
FROM Orders
GROUP BY id
) MinPurchaseOrder
ON C.Id = MinPurchaseOrder.Id
LEFT JOIN Orders O2
ON MinPurchaseOrder.pdate = O2.purchase_date
AND MinPurchaseOrder.id = O2.id
And the sql fiddle.