Solved

Sql to find top3 for each record

Posted on 2016-11-10
7
16 Views
Last Modified: 2016-11-10
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
0
Comment
Question by:johnnyg123
  • 3
  • 3
7 Comments
 
LVL 48

Expert Comment

by:PortletPaul
Comment Utility
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
 

Author Comment

by:johnnyg123
Comment Utility
did not like rn in where clause

got error message indicating invalid column
0
 
LVL 12

Expert Comment

by:Jeff Darling
Comment Utility
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
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 48

Expert Comment

by:PortletPaul
Comment Utility
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
 

Author Comment

by:johnnyg123
Comment Utility
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
 
LVL 48

Accepted Solution

by:
PortletPaul earned 500 total points
Comment Utility
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
 

Author Closing Comment

by:johnnyg123
Comment Utility
Thanks!!!!!!
0

Featured Post

Zoho SalesIQ

Hassle-free live chat software re-imagined for business growth. 2 users, always free.

Join & Write a Comment

Suggested Solutions

Naughty Me. While I was changing the database name from DB1 to DB_PROD1 (yep it's not real database name ^v^), I changed the database name and notified my application fellows that I did it. They turn on the application, and everything is working. A …
Ever needed a SQL 2008 Database replicated/mirrored/log shipped on another server but you can't take the downtime inflicted by initial snapshot or disconnect while T-logs are restored or mirror applied? You can use SQL Server Initialize from Backup…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now