Click here to Skip to main content
15,881,803 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
TransID	        Date
0000018801	2017-08-29 00:00:00.000
0000025950	2017-09-18 00:00:00.000
0000066677	2017-12-07 00:00:00.000
0000096617	2018-02-05 00:00:00.000
0000181068	2018-08-02 00:00:00.000
0000183129	2018-08-07 00:00:00.000
0000206606	2018-09-27 00:00:00.000
0000215028	2018-10-15 00:00:00.000
0000232571	2018-10-31 00:00:00.000
0000260763	2018-11-21 00:00:00.000
0000259321	2018-12-07 00:00:00.000
0000260762	2018-12-11 00:00:00.000


Select TransID,Date from #RNT1  group by TransID,Date Having Date=max(Date)


I want to get the last id with max date "0000260762"

What I have tried:

<pre>Select TransID,Date from #RNT1  group by TransID,Date Having Date=max(Date)
Posted
Updated 19-Dec-18 8:36am

Try:
SQL
SELECT TOP 1 TransID, [Date] FROM #RNT1 ORDER BY [Date] DESC
 
Share this answer
 
v2
Comments
Herman<T>.Instance 19-Dec-18 11:27am    
Performance wise the BEST option!
MadMyche 19-Dec-18 11:51am    
Based on?
Herman<T>.Instance 19-Dec-18 11:57am    
Only the last record will be taken from the db since the query asks for DESCENDING order. Despite the size of the collection. You find the MAX value in a blink of an eye. MAX (in the past at least) was a guaranteed table scan. The larger the collection, the longer it took.
MadMyche 19-Dec-18 12:26pm    
There is no guarantee that the last date will be the on the last record inserted. There are also no keys mentioned, which could change all of that up. While the Max() may be easy to find, the ORDER BY automatically generates a cursor
Herman<T>.Instance 20-Dec-18 4:44am    
ORDER BY DESCENDING. That is a guarantee! If the field is Indexed is not guaranteed
There are a few ways this could be implemented, I will give the 2 most common ways; Option 1 is to use a Top (1) / Order By method and Option 2 is to use a SubQuery with Aggregate method. Both of these will give the same correct results.

Option 1 is easier to code; however, takes a performance hit as it internally generates a cursor to perform the sorting. Option 2 may be a little harder to code, but has a much lower query cost (a unitless measure of overall cost, originally it was based on seconds to execute... in the 1990s)

I tested with your data, first with TransID as a BIGINT and then again as CHAR(10). Results were near identical, with the QueryCost of Option1/Option2 = 2.23. I also tried with TransID as a Primary Key and a Unique Clustered index on (TransID, [Date]). Query ratio changed to 2.25 to 1.

Testing Scripts
SQL
DECLARE @Rnt1 TABLE (
	TransID	CHAR(10) NOT NULL ,
	[Date]	Date NULL
)

INSERT @Rnt1
VALUES	('0000018801','2017/08/29')
,		('0000025950','2017/09/18')
,		('0000066677','2017/12/07')
,		('0000096617','2018/02/05')
,		('0000181068','2018/08/02')
,		('0000183129','2018/08/07')
,		('0000206606','2018/09/27')
,		('0000215028','2018/10/15')
,		('0000232571','2018/10/31')
,		('0000260763','2018/11/21')
,		('0000259321','2018/12/07')
,		('0000260762','2018/12/11')

-- [=====[ Option 1 ]=====]
SELECT	TOP 1 TransID, [Date] 
FROM		@RNT1 
ORDER BY	[Date] DESC

-- [=====[ Option 2 ]=====]
SELECT	TransID,[Date]
FROM		@RNT1
WHERE	[Date]= (SELECT Max([Date]) FROM @Rnt1)
 
Share this answer
 
Comments
[no name] 19-Dec-18 12:01pm    
Both SELECT do have at least the same execution plan. So I assume they are same efficient. Anyway a 5.
Wendelius 19-Dec-18 14:37pm    
Agree, there are lots of ways of doing this but these two are probable the easiest and efficient.
I want to get the last id with max date

From your question I got the impression that a single date could have multiple rows containing different values in TransId. If this is the case, then you should ensure that you really fetch the highest id value. To do this you need to add extra conditions or sorting to pick the correct value.

Modified from the queries already provided in the previous post, you could use something like
SQL
-- [=====[ Option 1 ]=====]
SELECT	TOP 1 
        TransID, [Date] 
FROM    #RNT1 
ORDER BY [Date] DESC, 
         TransID DESC

-- [=====[ Option 2 ]=====]
SELECT TOP 1 
       TransID, [Date]
FROM   #RNT1
WHERE  [Date]= (SELECT Max([Date]) FROM #RNT1)
ORDER BY TransID DESC


To add some data to the conversation about the performance, you could create some test rows:
SQL
CREATE TABLE #RNT1 (
	TransID	CHAR(10) NOT NULL ,
	[Date]	Date NULL
)

DECLARE  @counter int
BEGIN
   SET @counter = 1;
   WHILE @counter < 10000000 
   BEGIN
		INSERT INTO #RNT1 VALUES (RAND()*1000000, GETDATE()-RAND()*500);
		SET @counter = @counter + 1;
   END;
END;

If you investigate the plans, they look very different
Option 1
--------
|--Sort(TOP 1, ORDER BY:([tempdb].[dbo].[#RNT1].[Date] DESC, [tempdb].[dbo].[#RNT1].[TransID] DESC))
     |--Table Scan(OBJECT:([tempdb].[dbo].[#RNT1]))

Option 2
--------
|--Sort(TOP 1, ORDER BY:([tempdb].[dbo].[#RNT1].[TransID] DESC))
     |--Nested Loops(Inner Join, WHERE:([Expr1006]=[tempdb].[dbo].[#RNT1].[Date]))
          |--Stream Aggregate(DEFINE:([Expr1006]=MAX([tempdb].[dbo].[#RNT1].[Date])))
          |    |--Table Scan(OBJECT:([tempdb].[dbo].[#RNT1]))
          |--Table Scan(OBJECT:([tempdb].[dbo].[#RNT1]))

So what is the effect in practice, with the test cases generated above, they perform almost identically

Option 1
--------
Table '#RNT1'. Scan count 1, logical reads 28572, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 1515 ms,  elapsed time = 1525 ms.

Option 2
--------
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 1 ms.
Table '#RNT1'. Scan count 2, logical reads 57144, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 1594 ms,  elapsed time = 1593 ms.

As already pointed out by @MadMyche both statements use full table scans since no indices are present. The second query does the scan twice resulting in much higher logical IO. However this performance penalty is compensated with more efficient aggregation in joining.

But as said in the beginning the most important thing is that you get the correct results if multiple rows exist with a same date.
 
Share this answer
 
Comments
[no name] 19-Dec-18 16:40pm    
A 5 for your Information. For me "[=====[ Option 2 ]=====]" makes no sense in two Points:
a.) SELECT TOP
b.) ORDER BY

From my Point of view "WHERE [Date]= (SELECT Max([Date]) FROM #RNT1)" is enough. Where I'm wrong, what I do not understand here? Thanks in advance.

[Edit]
SELECT TOP I see now the reason...
Wendelius 19-Dec-18 23:26pm    
Thanks :)

You spotted the reason for the TOP already but for others who may wonder the same:

In Option 2 the ordering is done for the secondary sort field. The WHERE clause selects rows only for a single day while ORDER BY + TOP causes the highest TransId within that day to be returned .

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900