Postgresql getting other information from max tuple - sql

Say you have a table with studentID, class, grade. I want the maximum grade for each class. This is easy, just group by class and get max(grade). But the problem I'm having is how to also get the studentID.

Instead of using an aggregate function, you could use window functions:
SELECT class, grade, studentId
FROM (SELECT class, grade, studentId,
RANK() OVER (PARTITION BY class ORDER BY grade DESC) rk
FROM students)
WHERE rk = 1

I think distinct on is a good way to go:
select distinct on (s.class) s.*
from students
order by s.class, s.grade desc;
However you probably want all students for each class with the maximum grade. If so, Mureinik's solution is better.

Related

Retrieve attribute with max function

How retrieve other attribute with max function like max salary with name.
to retrieve max salary along with their name please help anyone.
If my understanding of the question is correct, you can use something like this:
select name, salary from table where salary = (select max(salary) from table)
With SalaryOrder AS (
Select name, salary, Row_Number() Over(Order By salary Desc) RN
From table
)
Select /*the top clause is needed as described below*/ Top (1) *
From SalaryOrder Where RN = 1
this query may return more than a record when existing people with the same salary.
To solve this you can add more orders in CTE or use Top one to pick a random record.
RANK() should be an efficient way to get name where salary is MAX. Using sub-query will also get us the same result but it will take more time than RANK() in some cases.
Query:
SELECT name, salary
FROM
(
SELECT name, salary, RANK() over(ORDER BY salary DESC) AS rnk
FROM your_table
) AS a
WHERE rnk=1
Look at the db<>fiddle with time consumption. (The time may vary for different runs)

Why doesn't DISTINCT work in this case? (SQL)

SELECT DISTINCT
employees.departmentname,
employees.firstname,
employees.salary,
employees.departmentid
FROM employees
JOIN (
SELECT MAX(salary) AS Highest, departmentID
FROM employees
GROUP BY departmentID
) departments ON employees.departmentid = departments.departmentid
AND employees.salary = departments.highest;
Why doesn't the DISTINCT work here?
I'm trying to have each department to show only once because the question is asking the highest salary in each department.
Use the ROW_NUMBER() function, as in:
select departmentname, firstname, salary, departmentid
from (
select e.*,
row_number() over(partition by departmentid, order by salary desc) as rn
from employees e
) x
where rn = 1
I'm trying to have each department to show only once because the question is asking the highest salary in each department.
Use window functions:
SELECT e.*
FROM (SELECT e.*,
ROW_NUMBER() OVER (PARTITION BY departmentID ORDER BY salary DESC) as seqnum
FROM employees e
) e
WHERE seqnum = 1;
This is guaranteed to return one row per department, even when there are ties. If you want all rows when there are ties, use RANK() instead.
Why doesn't the DISTINCT work here?
DISTINCT is not a function; it is a keyword that will eliminate duplicate rows when ALL the column values are duplicates. It does NOT apply to a single column.
The DISTINCT keyword has "worked" (i.e. done what it is intended to do) because there are no rows where all the column values are a duplicate of another row's values.
However, it hasn't solved your problem because DISTINCT is not the correct solution to your problem. For that, you want to "fetch the row which has the max value for a column [within each group]" (as per this question).
Gwen, Elena and Paula all have the same salary
and they are in the same department

Query without partition by or functions like rank()

Suppose we have the table students (name, grade, group, year)
We want a query that ranks for each group the corresponding students.
I know that this can be done easy with rank() OVER ( partition by group order by grade DESC ). But I think that this can also be done with a self join or a subquery. Any ideas?
The equivalent to rank() is:
select s.*,
(select 1 + count(*)
from students s2
where s2.group = s.group and
s2.grade > s.grade
) as rank
from students s;

Trying to get the max from a group of aggregates

Here my schema: Exams(int students, int scores)
I am writing a SQL query to find the greatest spread between a student's score.
I have been able to generate a query that has the student id and their spread using this query:
select student, max(score) - min(score) from exams group by student;
Now this is where I am stumped. How do I get the maximum value of the spreads? More specifically, I don't really understand what to put in my select statement that would be outside my initial query.
You can also use a subquery:
select max(spread)
from (
select student, max(score) - min(score) as spread from exams group by student
) x;
Try this:
select student, max(score) - min(score) as SPREAD
from exams
group by student
order by (max(score) - min(score)) DESC
This will at least show the results from highest to lowest

Get details semester wise highest marks without cursor

I have two tables.
Student (Roll_id,Student_name)
Student_mark (roll_id, semester, marks, subject)
I want student details who has got highest marks IN semester AND subject wise WITH their roll_id,mark,semester,subject
using that two table.
can we get results without using cursor?.
You can use the RANK() function to put the students in order by mark (partitioned by semester and subject):
WITH RankedResults AS
( SELECT s.Roll_ID,
s.Student_Name,
sm.Semester,
sm.Subject,
sm.Marks,
StudentRank = RANK() OVER(PARTITION BY sm.Semester, sm.Subject ORDER BY sm.Marks DESC)
FROM Student s
INNER JOIN Student_Mark sm
ON s.Roll_ID = sm.Roll_ID
)
SELECT Roll_ID, Student_name, Semester, Subject, Marks
FROM RankedResults
WHERE StudentRank = 1;
Example on SQL Fiddle