Haminteu
Haminteu

Reputation: 1334

Get the latest records per Group By SQL

I have the following table:

CREATE TABLE orders (
    id INT PRIMARY KEY IDENTITY,
    oDate DATE NOT NULL,
    oName VARCHAR(32) NOT NULL,
    oItem INT,
    oQty INT
    -- ...
);


INSERT INTO orders
  VALUES
(1, '2016-01-01', 'A', 1, 2),
(2, '2016-01-01', 'A', 2, 1),
(3, '2016-01-01', 'B', 1, 3),
(4, '2016-01-02', 'B', 1, 2),
(5, '2016-01-02', 'C', 1, 2),
(6, '2016-01-03', 'B', 2, 1),
(7, '2016-01-03', 'B', 1, 4),
(8, '2016-01-04', 'A', 1, 3)
;

I want to get the most recent rows (of which there might be multiple) for each name. For the sample data, the results should be:

id oDate oName oItem oQty ...
5 2016-01-02 C 1 2
6 2016-01-03 B 2 1
7 2016-01-03 B 1 4
8 2016-01-04 A 1 3

The query might be something like:

SELECT oDate, oName, oItem, oQty, ...
  FROM orders
  WHERE oDate = ???
  GROUP BY oName
  ORDER BY oDate, id

Besides missing the expression (represented by ???) to calculate the desired values for oDate, this statement is invalid as it selects columns that are neither grouped nor aggregates.

Does anyone know how to do get this result?

Upvotes: 7

Views: 15932

Answers (5)

Mureinik
Mureinik

Reputation: 311308

The rank window clause allows you to, well, rank rows according to some partitioning, and then you could just select the top ones:

SELECT oDate, oName, oItem, oQty, oRemarks
FROM   (SELECT oDate, oName, oItem, oQty, oRemarks,
               RANK() OVER (PARTITION BY oName ORDER BY oDate DESC) AS rk
        FROM   my_table) t
WHERE  rk = 1

Upvotes: 14

Utsav
Utsav

Reputation: 8093

This is a generic query without using analytical function.

SQLFiddle Demo

SELECT a.*
FROM table1 a
INNER JOIN
    (SELECT max(odate) modate,
          oname,
          oItem
   FROM table1
   GROUP BY oName,
            oItem
    ) 
    b ON a.oname=b.oname
AND a.oitem=b.oitem
AND a.odate=b.modate

Upvotes: 3

shA.t
shA.t

Reputation: 16958

I think you need a query like this:

SELECT *
FROM (SELECT *,
        ROW_NUMBER() OVER (PARTITION BY oName ORDER BY oDate DESC) seq
    FROM yourTable) t
WHERE (seq <= 2)
ORDER BY oDate; 

Upvotes: 2

You have to use ROW_NUMBER in following:

select oDate, oName, oItem, oQty, oRemarks
from (
   select *, row_number() over(partition by oName, oItem order by oDate desc) rn  
   from #t
)x
where rn = 1
order by oDate

OUTPUT

oDate   oName   oItem   oQty    oRemarks    
2016-01-01  A   001     2                   
2016-01-01  A   002     1       test        
2016-01-02  C   001     2                   
2016-01-03  B   001     4                   
2016-01-03  B   002     1                   

Upvotes: 0

androidGenX
androidGenX

Reputation: 1148

Add a primary key suppose id field to the table and make it auto increment,. Then order by id you will get it. It is the traditional way. By using your table you can only order by oDate. But is is having same date multiple times, so it also won't solve your problem.

Upvotes: 2

Related Questions