Reputation: 2907
I have the following table:
ProductID, GroupID, Description
1 100 Blah blah
2 200 Blah blah
3 100 Blah blah
4 200 Blah blah
5 200 Blah blah
6 100 Blah blah
7 300 Blah blah
9 300 Blah blah
10 100 Blah blah
I need to run a query that gets the data for this table such that EACH GroupID is retrieved exactly once, and the top-most ProductID is chosen. Example is shown below
ProductID, GroupID, Description
10 100 Blah blah
5 200 Blah blah
9 300 Blah blah
Any thoughts on the best approach for this? The goal being that each time this query is run, it always gets the latest ProductID for each particular GroupID. There are a lot more fields in this table, but I'm simplifying it to this example which essentially illustrates the main problem I'm trying to solve
Thanks!
Upvotes: 0
Views: 734
Reputation: 10456
For tasks such as this one, I always love using Ranking:
SELECT ProductID, GroupID, Description FROM
(
SELECT
t.ProductID
,t.GroupID
,t.Description
,RANK() OVER (PARTITION BY t.GroupID ORDER BY t.ProductID DESC) [Rank]
FROM MyTableName t
) RawData
WHERE RANK = 1
In general, the inner query just gives ranks for each row in the context of it's GroupID
(this is done by RANK() OVER (PARTITION BY t.GroupID ORDER BY t.ProductID DESC
).
The wrapping query is just for filtering rows which have a rank of 1 i.e. where the productID
is highest in the context of the specific GroupID
.
You can view the results in this Fiddle demo
Upvotes: 1
Reputation: 89285
You can try this (not tested) :
SELECT t.ProductID, t.GroupID, t.Description
FROM MyTableName t
INNER JOIN
(SELECT MAX(ProductID) As ProductID, GroupID
FROM MyTableName
GROUP BY GroupID) as maxPerGroup
ON maxPerGroup.ProductID = t.ProductID
Upvotes: 1
Reputation: 3820
Try this query
select * from products;
+-----------+---------+-------------+
| productId | groupId | description |
+-----------+---------+-------------+
| 1 | 100 | hello |
| 2 | 200 | hello |
| 3 | 100 | hello |
| 4 | 200 | hello |
| 5 | 200 | hello |
| 6 | 100 | hello |
| 7 | 300 | hello |
| 8 | 300 | hello |
| 9 | 100 | hello |
| 10 | 200 | hello |
+-----------+---------+-------------+
select * from products where productId in (select MAX(productId) from products group by groupId) order by groupId ASC;
+-----------+---------+-------------+
| productId | groupId | description |
+-----------+---------+-------------+
| 9 | 100 | hello |
| 10 | 200 | hello |
| 8 | 300 | hello |
+-----------+---------+-------------+
Upvotes: 0
Reputation: 1453
Sorry first i cann't understand your question,so i am down Voted. Following is the edited correct and tested query.
your records:
select * from dbo.[Products]
Showing Distinct GroupID with top ProductID
;with cteProducts(ProductID , GroupID) AS
(
select max(ProductID) ProductID , GroupID
FROM dbo.Products od
Group by GroupID
)
SELECT p1.ProductID,p1.GroupID,p1.[Description] from Products p1
INNER JOIN cteProducts p2 on p1.ProductID=p2.ProductID
order by p1.ProductID Desc
Your required result executed here:
Upvotes: -1
Reputation: 1342
In PostgreSQL, this works. Please check in SQL Server -
select t.productid, t.groupid, t.description from t, (select max(productid) mp , groupid from t group by groupid) x where t.productid=x.mp;
;
productid | groupid | description
-----------+---------+-------------
5 | 200 | BLAH BLAH
9 | 300 | BLAH BLAH
10 | 100 | BLAH BLAH
(3 rows)
Upvotes: -1
Reputation: 788
You're going to want to use the OVER clause to partition the table by GroupId. This will get you a table with two columns, the productId and a rowNum. rowNum will be 1 for the highest ProductID in each GroupID. Next, you simply inner join to that table and get ProductIDs that have a rowNum of 1. More info on the OVER clause can be found here
SELECT yt1.*
FROM yourTable yt1
INNER JOIN (
SELECT ROW_NUMBER() OVER(PARTITION BY GroupID ORDER BY ProductId DESC) as rowNum
, ProductID FROM yourTable
)yt2
ON yt1.ProductID = yt2.ProductID
WHERE yt2.rowNum = 1
Upvotes: 1