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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.