Hannah
Hannah

Reputation: 293

SQL SELECT TOP 1 FOR EACH GROUP

I have an SQL Database and in it a table called InventoryAllocations. In the table I have multiple entries for DocumentID's and want to retrieve the last entry for each unique DocumentID. I can retrieve just one by doing

SELECT  top(1) [UID]
      ,[RecordStatusID]
      ,[CreatedDate]
      ,[CreatedTime]
      ,[CreatedByID]
      ,[OperationType]
      ,[InventoryLocationID]
      ,[DocumentTypeID]
      ,[DocumentID]
      ,[SOJPersonnelID]
      ,[InventorySerialisedItemID]
      ,[TransactionQty]
      ,[TransactionInventoryStatusID]
      ,[Completed]
      ,[CreatedByType]
      ,[RecordTimeStamp]
  FROM [CPData].[dbo].[InventoryAllocations]
  order by DocumentID desc

but I want it to bring back a list containing all the unique DocumentID's.

Upvotes: 29

Views: 87844

Answers (4)

Sean Lange
Sean Lange

Reputation: 33581

Basically like this.

with cte as
(
    SELECT [UID]
        , [RecordStatusID]
        , [CreatedDate]
        , [CreatedTime]
        , [CreatedByID]
        , [OperationType]
        , [InventoryLocationID]
        , [DocumentTypeID]
        , [DocumentID]
        , [SOJPersonnelID]
        , [InventorySerialisedItemID]
        , [TransactionQty]
        , [TransactionInventoryStatusID]
        , [Completed]
        , [CreatedByType]
        , [RecordTimeStamp]
        , ROW_NUMBER() over (partition by DocumentID order by RecordTimeStamp desc) as RowNum
    FROM   [CPData].[dbo].[InventoryAllocations]
)

select [UID]
    , [RecordStatusID]
    , [CreatedDate]
    , [CreatedTime]
    , [CreatedByID]
    , [OperationType]
    , [InventoryLocationID]
    , [DocumentTypeID]
    , [DocumentID]
    , [SOJPersonnelID]
    , [InventorySerialisedItemID]
    , [TransactionQty]
    , [TransactionInventoryStatusID]
    , [Completed]
    , [CreatedByType]
    , [RecordTimeStamp]
from cte
where RowNum = 1
order by DocumentID desc

Upvotes: 0

VB1
VB1

Reputation: 214

You can use a RowNumber() Window Function.

SELECT * FROM(
    SELECT 
            ROW_NUMBER() OVER(PARTITION BY [DOCUMENTID] ORDER BY [RecordTimeStamp] DESC) AS RowNumber, 
          ,[RecordStatusID]
          ,[CreatedDate]
          ,[CreatedTime]
          ,[CreatedByID]
          ,[OperationType]
          ,[InventoryLocationID]
          ,[DocumentTypeID]
          ,[DocumentID]
          ,[SOJPersonnelID]
          ,[InventorySerialisedItemID]
          ,[TransactionQty]
          ,[TransactionInventoryStatusID]
          ,[Completed]
          ,[CreatedByType]
          ,[RecordTimeStamp]
      FROM [CPData].[dbo].[InventoryAllocations] ) as A 
WHERE RowNumber = 1

 

Upvotes: 10

Vadim Loboda
Vadim Loboda

Reputation: 3101

SELECT TOP 1 WITH TIES 
    [UID]
    ,[RecordStatusID]
    ,[CreatedDate]
    ,[CreatedTime]
    ,[CreatedByID]
    ,[OperationType]
    ,[InventoryLocationID]
    ,[DocumentTypeID]
    ,[DocumentID]
    ,[SOJPersonnelID]
    ,[InventorySerialisedItemID]
    ,[TransactionQty]
    ,[TransactionInventoryStatusID]
    ,[Completed]
    ,[CreatedByType]
    ,[RecordTimeStamp]
FROM 
    [CPData].[dbo].[InventoryAllocations]
ORDER BY
    ROW_NUMBER() OVER(PARTITION BY DocumentID ORDER BY [RecordTimeStamp] DESC);

TOP 1 works with WITH TIES here.

WITH TIES means that when ORDER BY = 1, then SELECT takes this record (because of TOP 1) and all others that have ORDER BY = 1 (because of WITH TIES).

Upvotes: 65

Dibstar
Dibstar

Reputation: 2364

This gives each record a row, taking each document ID and then giving the latest created_date a row_number of 1, and each row before that an increment of 1. We then select the records with a rowno of 1 to get the latest created date per document ID:

SELECT [UID]
,[RecordStatusID]
,[CreatedDate]
,[CreatedTime]
,[CreatedByID]
,[OperationType]
,[InventoryLocationID]
,[DocumentTypeID]
,[DocumentID]
,[SOJPersonnelID]
,[InventorySerialisedItemID]
,[TransactionQty]
,[TransactionInventoryStatusID]
,[Completed]
,[CreatedByType]
,[RecordTimeStamp]
FROM
(
SELECT  
[UID]
,[RecordStatusID]
,[CreatedDate]
,[CreatedTime]
,[CreatedByID]
,[OperationType]
,[InventoryLocationID]
,[DocumentTypeID]
,[DocumentID]
,[SOJPersonnelID]
,[InventorySerialisedItemID]
,[TransactionQty]
,[TransactionInventoryStatusID]
,[Completed]
,[CreatedByType]
,[RecordTimeStamp]
,ROW_NUMBER() OVER (PARTITION BY DOCUMENT_ID ORDER BY CreatedDate) DESC AS ROWNO
FROM [CPData].[dbo].[InventoryAllocations] 
)
WHERE ROWNO = 1

Upvotes: 1

Related Questions