'SQL query to select distinct row with minimum value

I want an SQL statement to get the row with a minimum value.

Consider this table:

id  game   point
1    x      5
1    z      4
2    y      6
3    x      2
3    y      5
3    z      8

How do I select the ids that have the minimum value in the point column, grouped by game? Like the following:

id  game   point    
1    z      4
2    y      5
3    x      2   


Solution 1:[1]

Use:

SELECT tbl.*
FROM TableName tbl
  INNER JOIN
  (
    SELECT Id, MIN(Point) MinPoint
    FROM TableName
    GROUP BY Id
  ) tbl1
  ON tbl1.id = tbl.id
WHERE tbl1.MinPoint = tbl.Point

Solution 2:[2]

This is another way of doing the same thing, which would allow you to do interesting things like select the top 5 winning games, etc.

 SELECT *
 FROM
 (
     SELECT ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Point) as RowNum, *
     FROM Table
 ) X 
 WHERE RowNum = 1

You can now correctly get the actual row that was identified as the one with the lowest score and you can modify the ordering function to use multiple criteria, such as "Show me the earliest game which had the smallest score", etc.

Solution 3:[3]

This will work

select * from table 
where (id,point) IN (select id,min(point) from table group by id);

Solution 4:[4]

As this is tagged with sql only, the following is using ANSI SQL and a window function:

select id, game, point
from (
  select id, game, point, 
         row_number() over (partition by game order by point) as rn
  from games
) t
where rn = 1;

Solution 5:[5]

Ken Clark's answer didn't work in my case. It might not work in yours either. If not, try this:

SELECT * 
from table T

INNER JOIN
  (
  select id, MIN(point) MinPoint
  from table T
  group by AccountId
  ) NewT on T.id = NewT.id and T.point = NewT.MinPoint

ORDER BY game desc

Solution 6:[6]

SELECT DISTINCT 
FIRST_VALUE(ID) OVER (Partition by Game ORDER BY Point) AS ID,
Game,
FIRST_VALUE(Point) OVER (Partition by Game ORDER BY Point) AS Point
FROM #T

Solution 7:[7]

SELECT * from room
INNER JOIN
  (
  select DISTINCT hotelNo, MIN(price) MinPrice
  from room
 Group by hotelNo
  ) NewT   
 on room.hotelNo = NewT.hotelNo and room.price = NewT.MinPrice;

Solution 8:[8]

This alternative approach uses SQL Server's OUTER APPLY clause. This way, it

  1. creates the distinct list of games, and
  2. fetches and outputs the record with the lowest point number for that game.

The OUTER APPLY clause can be imagined as a LEFT JOIN, but with the advantage that you can use values of the main query as parameters in the subquery (here: game).

SELECT colMinPointID
FROM (
  SELECT game
  FROM table
  GROUP BY game
) As rstOuter
OUTER APPLY (
  SELECT TOP 1 id As colMinPointID
  FROM table As rstInner
  WHERE rstInner.game = rstOuter.game
  ORDER BY points
) AS rstMinPoints

Solution 9:[9]

This is portable - at least between ORACLE and PostgreSQL:

select t.* from table t 
where not exists(select 1 from table ti where ti.attr > t.attr);

Solution 10:[10]

Most of the answers use an inner query. I am wondering why the following isn't suggested.

select
   *
from
   table
order by
   point
fetch next 1 row only   // ... or the appropriate syntax for the particular DB

This query is very simple to write with JPAQueryFactory (a Java Query DSL class).

return new JPAQueryFactory(manager).
   selectFrom(QTable.table).
   setLockMode(LockModeType.OPTIMISTIC).
   orderBy(QTable.table.point.asc()).
   fetchFirst();

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Daniil Pastukhov
Solution 2
Solution 3 Eric Leschinski
Solution 4 a_horse_with_no_name
Solution 5 Community
Solution 6
Solution 7 josliber
Solution 8
Solution 9 thenor
Solution 10 Nathan