Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mysql - Get two greatest values from multiple columns

Tags:

sql

mysql

We can use GREATEST to get greatest value from multiple columns like below

SELECT GREATEST(mark1,mark2,mark3,mark4,mark5) AS best_mark FROM marks

But now I want to get two best marks from all(5) marks.

Can I do this on mysql query?

Table structure (I know it is wrong - created by someone):

student_id  | Name | mark1 | mark2 | mark3 | mark4 | mark5
like image 826
Logan Avatar asked May 21 '13 11:05

Logan


People also ask

How do you SELECT the top 2 maximum value in SQL?

2nd highest value in SQL using Max() function SELECT MAX (ProductID) FROM Production. WorkOrder WHERE ProductID NOT IN (SELECT MAX (ProductID) FROM Production. WorkOrder);

How do you SELECT the highest 3 values in SQL?

In sql server you could do select top 3 * from Test order by f1 desc . Other DBMS's have similar posibilities such as MySql's limit , Oracle's rownum etc. Save this answer.

Can we have 2 order by in MySQL?

Can we have 2 ORDER BY in MySQL? After the ORDER BY keyword, add the name of the column by which you'd like to sort records first (in our example, salary). Then, after a comma, add the second column (in our example, last_name ). You can modify the sorting order (ascending or descending) separately for each column.

Can we use Max in Where clause in MySQL?

The MAX() function is used with the WHERE clause to gain further insights from our data. In SQL, the MAX() function computes the highest or maximum value of numeric values in a column.


1 Answers

This is not the most elegant solution but if you cannot alter the table structure then you can unpivot the data and then apply a user defined variable to get a row number for each student_id. The code will be similar to the following:

select student_id, name, col, data
from
(
  SELECT student_id, name, col,
    data,
    @rn:=case when student_id = @prev then @rn else 0 end +1 rn,
    @prev:=student_id
  FROM 
  (
    SELECT student_id, name, col,
      @rn, 
      @prev,
      CASE s.col
        WHEN 'mark1' THEN mark1
        WHEN 'mark2' THEN mark2
        WHEN 'mark3' THEN mark3
        WHEN 'mark4' THEN mark4
        WHEN 'mark5' THEN mark5
      END AS DATA
    FROM marks
    CROSS JOIN 
    (
      SELECT 'mark1' AS col UNION ALL 
      SELECT 'mark2' UNION ALL 
      SELECT 'mark3' UNION ALL 
      SELECT 'mark4' UNION ALL 
      SELECT 'mark5'
    ) s
    cross join (select @rn := 0, @prev:=0) c
  ) s
  order by student_id, data desc
) d
where rn <= 2
order by student_id, data desc;

See SQL Fiddle with Demo. This will return the top 2 marks per student_id. The inner subquery is performing a similar function as using a UNION ALL to unpivot but you are not querying against the table multiple times to get the result.

like image 61
Taryn Avatar answered Oct 11 '22 15:10

Taryn