Selecting latest order

by ASH October 31, 2009 12:15

A common problem to solve is to list, for example the current price for a product or latest order for a customer or similar.
It is a problem which quickly can seem complex, but once understanding the situation, then – as everything else – it is relative simple, and I’ll show how using both window functions (in this instance, RANK) from SQL Server 2005+ and using a sub-query in case working on an earlier version, or other databases.

I’ll take offset in the Northwind database, which I’ve installed on a SQL Server 2008.
It has an Order table with a foreign key to a Customer table; however for this the Order table is the only one of interest:
The Order table contains the following information:
SELECT [OrderID]
      
,
[CustomerID]
      
,
[EmployeeID]
      
,
[OrderDate]
      
,
[RequiredDate]
      
,
[ShippedDate]
      
,
[ShipVia]
      
,
[Freight]
      
,
[ShipName]
      
,
[ShipAddress]
      
,
[ShipCity]
      
,
[ShipRegion]
      
,
[ShipPostalCode]
      
,
[ShipCountry]
  
FROM [Northwind].[dbo].[Orders]
 


In this situation, we’ll get the latest order per customer, but the problem is the same as if you’d need the current price – the only thing which differs will be the tables and where clauses and so on.
Solving the issue using the RANK window function, and a common table expression, it would look like this:

;WITH CTE AS (
SELECT 
RANK() OVER (Partition BY T1.CustomerID ORDER BY OrderDate DESCAS OrderRank
,
T1.
*
FROM 
Orders T1
)
SELECT FROM CTE WHERE OrderRank 
1
ORDER BY CustomerID
   

What happens here is that we use RANK to give us a number partitioned (grouped) by CustomerID and sorted by OrderDate descending. This will give each row selected the number/rank that order is historically, from newest to earliest. That means each row which have the rank 1 will be the latest/newest order.
You can then expand on the joins inside/outside the common table expression to get information about customers or order details or what not.

It is also solvable without using the window function RANK, and would look for example something like this:

SELECT 
FROM 
Orders T1
INNER JOIN 
(
   
SELECT CustomerIDMAX(OrderDateAS 
OrderDate
   
FROM 
Orders T2
   
GROUP BY 
T2.CustomerID
T3 ON T3.OrderDate T1.OrderDate AND T1.CustomerID 
T3.CustomerID
ORDER BY T1.CustomerID
    

Here we utilize a sub-query where we select the CustomerID and the highest order date from Orders, which we then can join into Orders again with a self-join on customer id and order date.

Note that these are just examples. Many similar solutions exists, but they all follow the same methodology.
I’ve also not taken optimizaiton or anything like that into account. It was just to illustrate a solution to a common problem.

 

Comments

Add comment


 

  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen | Modified by Mooglegiant

About me

My real name is Allan Svelmøe Hansen.

I live in Denmark, where I work as a developer for hedal:kruse:brohus using SQL Server and the .NET framework since 2004.  My primary fields of expertise is back end data integration, database design and optimization. But I also work with website development as well as application/services for server and SEO of websites.

Disclaimer

The opinions expressed herein are my own personal opinions and thoughts and does not represent my employer's view in any way, nor are my results guarentees for all situations.

Content is presented “as is”, with no warranty.