Sql to find top3 for each record

Here is some sample data from a table named Customer Orders

CustomerID     CustomerOrderDate    OrderAmount
1                         10/11/2016                     300
1                         10/25/2016                     200
1                          9/01/2016                      700
1                         8/21/2016                       375
1                         5/31/2016                       6666
1                         02/01/2016                     433
2                         11/01/2016                     1000
2                         10/01/2016                     790

(Note: There are thousands of customers...to save space I just included 2 customers  

Trying to write a query that would list each customer id along with the last 3 orders along with sales amount for each of those orders

 (possible customers have less than 3 orders... would like the order dates to appear in the fields in reverse chronological order)



Using the above data I would like the query results to be

CustomerID  LastOrder1    SalesAmount1  LastOrder2    SalesAmount2        LastOrder3   SalesAmount3
1                     09/01/2016    700                     10/11/2016      300                         10/25/2016     200
2                     10/01/2016    790                    11/01/2016      1000
johnnyg123Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

PortletPaulfreelancerCommented:
use ROW_NUMBER()
SELECT
        CustomerID
      , CustomerOrderDate
      , OrderAmount
      , ROW_NUMBER() OVER (PARTITION BY CustomerID 
                           ORDER BY CustomerOrderDate DESC) AS rn
FROM [orders] o
WHERE rn <= 3
ORDER BY
        CustomerID
      , rn

Open in new window

inside the OVER() the partition restarts counting at 1 for each customerid and the order by determines the way the numbers increment (most recent dates achieved via DESCending order)
0
johnnyg123Author Commented:
did not like rn in where clause

got error message indicating invalid column
0
Jeff DarlingDeveloper AnalystCommented:
Here is an old piece of code that I had from SQL server 2000.

I modified it to use your test data.  

-- Create a  table 
create Table #Table1 (
    CustomerID varchar(20)
    ,CustomerOrderDate datetime
    ,OrderAmount money
	);
	
create Table #Table2 (
    Rownumber INTEGER IDENTITY(1, 1)
    ,CustomerID varchar(20)
    ,CustomerOrderDate datetime
    ,OrderAmount money
	);	
	
	
-- add some records 
Insert into #Table1 (CustomerID,CustomerOrderDate,OrderAmount) values  ('1','10/11/2016',300)
Insert into #Table1 (CustomerID,CustomerOrderDate,OrderAmount) values  ('1','10/25/2016',200)
Insert into #Table1 (CustomerID,CustomerOrderDate,OrderAmount) values  ('1','9/01/2016',700)
Insert into #Table1 (CustomerID,CustomerOrderDate,OrderAmount) values  ('1','8/21/2016',375)
Insert into #Table1 (CustomerID,CustomerOrderDate,OrderAmount) values  ('1','5/31/2016',6666)
Insert into #Table1 (CustomerID,CustomerOrderDate,OrderAmount) values  ('1','2/01/2016',433)
Insert into #Table1 (CustomerID,CustomerOrderDate,OrderAmount) values  ('2','11/01/2016',1000)
Insert into #Table1 (CustomerID,CustomerOrderDate,OrderAmount) values  ('2','10/01/2016',790)

Insert into #Table2 (CustomerID,CustomerOrderDate,OrderAmount)
select CustomerID,CustomerOrderDate,OrderAmount from #Table1 order by CustomerID,OrderAmount desc

Select CustomerID,CustomerOrderDate,OrderAmount from 
(
SELECT    t.CustomerID, CustomerOrderDate,OrderAmount,t.Rownumber - o.Offset as SetRowNumber
FROM      #Table2 t
          INNER JOIN (
            SELECT    CustomerID, MIN(Rownumber) - 1 AS Offset
            FROM      #Table2
            GROUP BY  CustomerID
          ) o ON o.CustomerID = t.CustomerID    
) G1
Where SetRowNumber <4

drop table #Table1
drop table #Table2

Open in new window

0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

PortletPaulfreelancerCommented:
My fault... sorry..
SELECT
        CustomerID
      , CustomerOrderDate
      , OrderAmount
FROM (SELECT
                CustomerID
              , CustomerOrderDate
              , OrderAmount
                row_number () OVER (PARTITION BY CustomerID
        ORDER BY CustomerOrderDate DESC) AS rn
        FROM [orders] o) d
WHERE rn <= 3
ORDER BY
        CustomerID
      , CustomerOrderDate DESC

Open in new window

0
johnnyg123Author Commented:
Actually did get it to work using the following

SELECT
        CustomerID
      , CustomerOrderDate
      , OrderAmount From

(

SELECT
        CustomerID
      , CustomerOrderDate
      , OrderAmount
      , ROW_NUMBER() OVER (PARTITION BY CustomerID
                           ORDER BY CustomerOrderDate DESC) AS rn
FROM [orders])  o
WHERE rn <= 3


However,

Not sure how to get in the format

  CustomerID  LastOrder1    SalesAmount1  LastOrder2    SalesAmount2        LastOrder3   SalesAmount3
 1                     09/01/2016    700                     10/11/2016      300                         10/25/2016     200
 2                     10/01/2016    790                    11/01/2016      1000
0
PortletPaulfreelancerCommented:
oh! I'm sorry. to be honest I didn't even notice that portion of the question.

I will suggest using "conditional aggregates" for that part:
SELECT
        CustomerID
      , max(case when rn = 1 then CustomerOrderDate end) as LastOrder1
      , max(case when rn = 1 then OrderAmount end)       as SalesAmount1
      , max(case when rn = 2 then CustomerOrderDate end) as LastOrder2
      , max(case when rn = 2 then OrderAmount end)       as SalesAmount2
      , max(case when rn = 3 then CustomerOrderDate end) as LastOrder3
      , max(case when rn = 3 then OrderAmount end)       as SalesAmount3
FROM (SELECT
                CustomerID
              , CustomerOrderDate
              , OrderAmount
                row_number () OVER (PARTITION BY CustomerID
        ORDER BY CustomerOrderDate DESC) AS rn
        FROM [orders] o) d
WHERE rn <= 3
GROUP BY
        CustomerID

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
johnnyg123Author Commented:
Thanks!!!!!!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft SQL Server 2008

From novice to tech pro — start learning today.