10

I have the following table

CREATE TABLE Test
    (`Id` int, `value` varchar(20), `adate` varchar(20))
;

INSERT INTO Test
    (`Id`, `value`, `adate`)
VALUES
    (1, 100, '2014-01-01'),
    (1, 200, '2014-01-02'),
    (1, 300, '2014-01-03'),
    (2, 200, '2014-01-01'),
    (2, 400, '2014-01-02'),
    (2, 30 , '2014-01-04'),
    (3, 800, '2014-01-01'),
    (3, 300, '2014-01-02'),
    (3, 60 , '2014-01-04')
;

I want to achieve the result which selects only Id having max value of date. ie

Id ,value ,adate

 1, 300,'2014-01-03'     
 2, 30 ,'2014-01-04'     
 3, 60 ,'2014-01-04'

how can I achieve this using group by? I have done as follows but it is not working.

Select Id,value,adate
from Test
group by Id,value,adate
having adate = MAX(adate)

Can someone help with the query?

johnnyRose
  • 6,243
  • 16
  • 40
  • 58
NewtonCode
  • 942
  • 4
  • 12
  • 20

4 Answers4

13

Select the maximum dates for each id.

select id, max(adate) max_date
from test
group by id

Join on that to get the rest of the columns.

select t1.*
from test t1
inner join (select id, max(adate) max_date
            from test
            group by id) t2
on t1.id = t2.id and t1.adate = t2.max_date;
Mike Sherrill 'Cat Recall'
  • 82,047
  • 16
  • 110
  • 161
  • What if `adate` must be determined through 2 other columns that must be handled as union? – Fabian Picone Sep 01 '17 at 11:31
  • 1
    @FabianPicone: The principle is the same. Write a query that returns one row per "id", and join on it. You might have to write the UNION query, and then SELECT from it. (SELECT * FROM (SELECT...UNION SELECT...)) – Mike Sherrill 'Cat Recall' Sep 01 '17 at 12:43
5

Please try:

select 
  * 
from 
  tbl a
where 
  a.adate=(select MAX(adate) from tbl b where b.Id=a.Id)
TechDo
  • 17,374
  • 3
  • 46
  • 61
5

If you are using a DBMS that has analytical functions you can use ROW_NUMBER:

SELECT  Id, Value, ADate
FROM    (   SELECT  ID,
                    Value,
                    ADate,
                    ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Adate DESC) AS RowNum
            FROM    Test
        ) AS T
WHERE   RowNum = 1;

Otherwise you will need to use a join to the aggregated max date by Id to filter the results from Test to only those where the date matches the maximum date for that Id

SELECT  Test.Id, Test.Value, Test.ADate
FROM    Test
        INNER JOIN
        (   SELECT  ID, MAX(ADate) AS ADate
            FROM    Test
            GROUP BY ID
        ) AS MaxT
            ON MaxT.ID = Test.ID
            AND MaxT.ADate = Test.ADate;
GarethD
  • 61,378
  • 9
  • 75
  • 114
-1

I would try something like this

Select  t1.Id, t1.value, t1.adate
from    Test as t1
where   t1.adate = (select max(t2.adate) 
                    from Test as t2
                    where t2.id = t1.id)