Solved

Sql to find top3 for each record

Posted on 2016-11-10
7
28 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
ID: 41882914
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
ID: 41882943
did not like rn in where clause

got error message indicating invalid column
0
 
LVL 12

Expert Comment

by:Jeff Darling
ID: 41882948
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
Back Up Your Microsoft Windows Server®

Back up all your Microsoft Windows Server – on-premises, in remote locations, in private and hybrid clouds. Your entire Windows Server will be backed up in one easy step with patented, block-level disk imaging. We achieve RTOs (recovery time objectives) as low as 15 seconds.

 
LVL 48

Expert Comment

by:PortletPaul
ID: 41882951
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
ID: 41882966
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
ID: 41882984
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
ID: 41883022
Thanks!!!!!!
0

Featured Post

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

After restoring a Microsoft SQL Server database (.bak) from backup or attaching .mdf file, you may run into "Error '15023' User or role already exists in the current database" when you use the "User Mapping" SQL Management Studio functionality to al…
How to leverage one TLS certificate to encrypt Microsoft SQL traffic and Remote Desktop Services, versus creating multiple tickets for the same server.
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

831 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