use RANK or DENSE_RANK along with aggregate function - oracle

I have a table with the following data:
SCORE ROW_ID NAME
0.4 1011 ABC
0.95 1011 DEF
0.4 501 GHI
0.95 501 XYZ
At any point of time, i only need single row of data with maximum score, if there has more than 1 records, take the one with minimum row_id.
Is it possible to achieve by using RANK or DENSE_RANK function? How about partition by?
MAX(score) keep(dense_rank first order by row_id)

You are looking for max score, one row, so use row_number():
select score, row_id, name
from (select t.*, row_number() over (order by score desc, row_id) rn from t)
where rn = 1
demo
You can use rank and dense_rank in your example, but they can return more than one row, for instance when you add row (0.95, 501, 'PQR') to your data.
keep dense_rank is typically used when searched value is other than search criteria, for instance if we look for salary of employee who works the longest:
max(salary) keep (dense_rank first order by sysdate - hiredate desc)
max in this case means that if there are two or more employees who works longest, but exactly the same number of days than we take highest salary.
max(salary)
keep (dense_rank first order by sysdate - hiredate desc)
over (partition by deptno)
This is the same as above, but salary of longest working employees is shown for each department separately. You can even use empty over() to show salary of longest working employee in separate column except other data like name, salary, hire_date.

You dont need to use dense_rank. This would help
SELECT * FROM (
SELECT
SCORE,
ROW_ID
NAME
FROM T
ORDER BY SCORE DESC, ROW_ID DESC
)
WHERE ROWNUM = 1;

Related

Finding list of max average salary, department wise, whilst displaying both max average salary and department_id

When I try it without displaying department_id it works fine as :
SQL> SELECT MAX(AVG(SALARY)) FROM EMPLOYEE GROUP BY DEPARTMENT_ID;
MAX(AVG(SALARY))
----------------
800000
But when I want to display the department_id's too, it gives me error as follows:
SQL> SELECT DEPARTMENT_ID, MAX(AVG(SALARY)) FROM EMPLOYEE GROUP BY DEPARTMENT_ID;
SELECT DEPARTMENT_ID, MAX(AVG(SALARY)) FROM EMPLOYEE GROUP BY DEPARTMENT_ID
*
ERROR at line 1:
ORA-00937: not a single-group group function
Is there any explanation for this? What am I doing wrong? I went through answers of previous questions like this and tried their solutions but got same or some other error. Any help would be appreciated.
I suggest you use
SELECT department_id, avg_salary
FROM ( SELECT DEPARTMENT_ID,
AVG (SALARY) avg_salary,
RANK () OVER (ORDER BY AVG (salary) DESC) rnk
FROM EMPLOYEE
GROUP BY DEPARTMENT_ID)
WHERE rnk = 1;
i.e.
use your first query as a "source"
additionally, rank average salaries in descending order (using the rank analytic function)
select row which ranks as highest

In case second highest value is missing then use the highest value of salary from employee table

I have an employee table as below. As you can see that second highest salary is 200
Incase the second highest salary is missing then there will be only one row as shown at last . In this case the query should fetch only 100
I have written query as but it is not working. Please help! Thanks
select salary "SecondHighestSalary" from(
(select id,salary,rank() over(order by salary desc) rnk
from employee2)
)a
where (rnk) in coalesce(2,1)
I have also tried the following but it is fetching 2 rows but i need only 1
It sounds like you'd want something like
with ranked_emp as (
select e.*,
rank() over (order by e.sal desc) rnk,
count(*) over () cnt
from employee2 e
)
select salary "SecondHighestSalary"
from ranked_emp
where (rnk = 2 and cnt > 1)
or (rnk = 1 and cnt = 1)
Note that I'm still using rank since you're using that in your approach and you don't specify how you want to handle ties. If there are two employees with the same top salary, rank will assign both a rnk of 1 and no employee would have a rnk of 2 so the query wouldn't return any data. dense_rank would ensure that there was at least one employee with a rnk of 2 if there were employees with at least 2 different salaries. If there are two employees with the same top salary, row_number would arbitrarily assign one the rnk of 2. The query I posted isn't trying to handle those duplicate situations because you haven't outlined exactly how you'd want it to behave in each instance.
If you are in Oracle 12.2 or higher, you can try:
select distinct id,
nvl
(
nth_value(salary, 2) from first
over(partition by id
order by salary desc
range between unbounded preceding and unbounded
following),
salary
) second_max_salary
from employee2

Find second highest salary in each department using rank/dense_rank in hive

These were the two questions asked to me during an interview but only condition is to use rank/dense_rank.
Find second highest salary in each department using rank/dense_rank in
hive.
When there are sufficient records in each department.
When there is only 1 record in few departments.
Guide me if this is even valid or not.
If yes then what should be the queries for the same.
If you need to select all second salary employees then use
dense_rank() over(partition by department order by salary desc) = 2 filter. It will return all employees with second salary.
When there is only 1 record in the department (no second salary exists, one employee in the department), it will be ranked 1 and you will get no records for that department filtering by dense_rank = 2.
If you need to select only one record (not all employees) with second salary then row_number() over(partition by department order by salary desc) = 2 will work, but it will pick one random employee with second salary if there are many employees with second salary. Only one record will be marked with row_number = 2.
Try this:
WITH RESULT AS
(
SELECT salary, DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS SecondHighest FROM Employee
)
SELECT IFNULL(( SELECT salary FROM RESULT WHERE SecondHighest = 2 ORDER BY salary) , NULL) as SecondHighestSalary

Oracle SQL join query to find highest salary

So I have two tables salary and emp whose definition is shown as below
[
I am tring to create a query that Find the employee who draws the maximum salary and Display the employee details along with the nationality.
I created this query
select empcode,
max(basic) as "Highest Sal"
from salary
join emp on empcode;
Please help with this
Your query uses a simple aggregate max(basic) which would find the highest salary. Except you need to join to the EMP table to display other details. This means you can't use aggregation, because we need to GROUP BY the non-aggregated columns, which would make a nonsense of the query.
Fortunately we can solve the problem with an analytic function. The subquery selects all the relevant information and ranks each employee by salary, with a rank of 1 being the highest paid. We use rank() here because that will handle ties: two employees with the same basic will be in the same rank.
select empcode
, empname
, nationality
, "Highest Sal"
from (
select emp.empcode
, emp.empname
, emp.nationality
, salary.basic as "Highest Sal"
, rank() over (order by salary.basic desc ) as rnk
from salary join emp on emp.empcode = salary.empcode
)
where rnk = 1;
Find the employee who draws the maximum salary
An employee can have multiple salaries in your datamodel. An employee's (total) salary hence is the sum of these. You want to find the maximum salary per employee and show the employee(s) earning that much.
You can use MAX OVER to find the maximum sum:
select e.*, s.total_salary
from emp e
join
(
select
empcode,
sum(basic) as total_salary,
max(sum(basic)) over () as max_total_salary
from salary
) s on s.empcode = e.empcode and s.total_salary = s.max_total_salary
order by e.empcode;
Try this:
SELECT * FROM
(SELECT E.EmpCode, E.EmpName, E.DOB, E.DOJ, E.DeptCode, E.DesgCode, E.PhNo,
E.Qualification, E.Nationality, S.Basic, S.HRA, S.TA, S.UTA, S.OTRate
FROM EMP AS E JOIN SALARY AS S ON (E.EmpCode = S.EmpCode) order by S.Basic desc)
WHERE rownum = 1

Can anybody explain how this query works?

This is a SQL query to find the Nth highest salary of employees:
SELECT *
FROM emp t
WHERE 1 = (SELECT COUNT(DISTINCT sal)
FROM emp t2
WHERE t2.sal > t.sal)
I don't know how it returns the result. If you put 1 in the WHERE clause, it will return the second highest, and for 2 the 3rd highest salary, and so on.
Please explain the query as I am unsure.
Let me start by saying a better way to write the query is:
select e.*
from (select e.*, dense_rank() over (order by sal desc) as seqnum
from emp e
) e
where seqnum = 2;
What is your query doing? Go step-by-step:
The outer query is doing a comparison for every row in emp.
The comparison counts the number of distinct salaries that are larger than the salary in the row.
The row is kept if there is exactly 1 salary that is larger.
In other words, this is keeping all rows that have the second largest salary. dense_rank() is a much saner way to write the query (and it has better performance too).

Resources