3

I have a table similar to this (3 rows, 4 columns: id, name, gradeA, gradeB):

id    name    gradeA    gradeB
------------------------------
1     David   59        78
2     Anna    66        92
3     David   22        89

I'm looking for a query that will give me 1 numeric property for the highest grade by in the whole table by condition. for example:

What is the highest grade for any student named David?

The answer should be { maxGrade: 89 }

Note: grades are stored as varchar values and should be cast to numeric values for comparison

5
  • 1
    How come "grades are stored as varchar values and should be cast to numeric values for comparison"? I'd use int data type instead. Commented Aug 18, 2020 at 8:42
  • Thats a 'given'. I did not configure the table and they are 'natively' used as string values in other places. Commented Aug 18, 2020 at 8:45
  • above JSON is a filed in your table or you have a table with 4 fields Commented Aug 18, 2020 at 8:47
  • The above example reflects a table with 3 rows and 4 columns: id, name, gradeA, gradeB Commented Aug 18, 2020 at 8:48
  • "grades are stored as varchar values" - do you have a chance to fix that broken data model? Never store numbers as varchars. Just don't Commented Aug 18, 2020 at 9:00

3 Answers 3

6

You need to combine max() with greatest()

select max(greatest(gradea::int, gradeb::int)) as max_grade
from the_table
where name = 'David';

If you need a JSON result (because you wrote: result should be {maxGrade: 89}), you can wrap that query and convert the row to JSON:

select to_jsonb(t) 
from (
  select max(greatest(gradea::int, gradeb::int)) as "maxGrade"
  from the_table
  where name = 'David'
) t;
Sign up to request clarification or add additional context in comments.

2 Comments

@user11350468 because without the max() you get two rows with. One with 89 and one with 78
Yes, Got it, I forgot about the duplicate names.., Thanks for your time
1

I would recommend a lateral join:

select max(grade::int) as max_grade
from t cross join lateral
     (values (gradea), (gradeb)) v(grade)
where name = 'David';

In particular, this works if any of the grades are NULL.

It can also easily be tweaked to get which grade is the maximum:

select v.*
from t cross join lateral
     (values ('a', gradea), ('b', gradeb)) v(which, grade)
where name = 'David'
order by grade::int desc
limit 1

2 Comments

What would be the expected output of the 2nd 'which' query?
Why don't you run it to see? It puts the name of the columns that has the maximum.
1

Try the below:

We shall achieve with GREATEST and MAX:

  1. We can make use of GREATEST to return the large value between the columns grade A and grade B for every user record
  2. And use MAX to return the maximum grade if more than user matches with the same name.
SELECT 
  MAX(GREATEST(gradeA::integer, gradeB::integer)) as maxGrade 
FROM 
  "table_name" 
WHERE 
  "table_name"."name" = 'David';

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.