3

I have a table as following:

ID     NAME     AMOUNT
______________________
 1      A          3
 1      B          4
 2      C          18
 4      I          2 
 4      P          9

And I want the min(Amount) for each ID but I still want to display its Name. So I want this:

 ID     NAME     min(AMOUNT)
______________________
 1      A          3
 2      C          18
 4      I          2 

ID's can occur multiple times, Names too. I tried this:

SELECT ID, NAME, min(AMOUNT) FROM TABLE
GROUP BY ID

But of course its an error because I have to

GROUP BY ID, NAME

But then I get

 ID     NAME     AMOUNT
______________________
 1      A          3
 1      B          4
 2      C          18
 4      I          2 
 4      P          9

And I understand why, it looks for the min(AMOUNT) for each combination of ID + NAME. So my question is basically, how can I select multiple column (ID, NAME, AMOUNT) and get the minimum for only one column, still displaying the others?

Im new to SQL but I cant seem to find an answer..

3
  • Still display which others Commented May 27, 2020 at 8:15
  • 1
    Which dbms are you using? Commented May 27, 2020 at 8:20
  • 1
    If you add the row (1, W, 3), what's the expected result? Commented May 27, 2020 at 8:21

3 Answers 3

6

If you are using PostgreSQL, SQL Server, MySQL 8.0 and Oracle then try the following with window function row_number().

in case you have one id with similar amount then you can use dense_rank() instead of row_number()

Here is the demo.

select
    id,
    name,
    amount
from
(
    select
        *,
        row_number() over (partition by id order by amount) as rnk
    from yourTable
) val
where rnk = 1

Output:

| id  | name | amount |
| --- | ---- | ------ |
| 1   | A    | 3      |
| 2   | C    | 18     |
| 4   | I    | 2      | 

Second Option without using window function

select
    val.id,
    t.name,
    val.amount
from myTable t
join
(
  select
        id,
        min(amount) as amount
    from myTable
    group by
        id
) val
on t.id = val.id
and t.amount = val.amount
Sign up to request clarification or add additional context in comments.

Comments

3

In many databases, the most efficient method uses a correlated subquery:

select t.*
from t
where t.amount = (select min(t2.amount) from t t2 where t2.id = t.id);

In particular, this can take advantage of an index on (id, amount).

Comments

1

You did not specify your db vendor. If it is luckily Postgres, the problem can be also solved without nested subquery using proprietary distinct on clause:

with t(id,name,amount) as (values
 (1,      'A',          3),
 (1,      'B',          4),
 (1,      'W',          3),
 (2,      'C',          18),
 (4,      'I',          2),
 (4,      'P',          9)
)
select distinct on (id, name_of_min) id 
     , first_value(name) over (partition by id order by amount) as name_of_min
     , amount
from t
order by id, name_of_min

Just for widening knowledge. I don't recommend using proprietary features. first_value is standard function but to solve problem in simple query is still not enough. @zealous' answer is perfect.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.