calculate highest nth salary using sql - sql

I want to calculate highest nth salary in Oracle. I've already done with my solution but on google I found one query doing the same thing.
Here is the query
SELECT *
FROM Employee Emp1
WHERE (N - 1) = (SELECT COUNT(DISTINCT(Emp2.orig_salary))
FROM Employee Emp2
WHERE emp2.orig_salary > emp1.orig_salary)
Data
ID Name Birth Orig_Salary
2 John 15-JUL-97 2341
3 Joe 25-JAN-86 4321
4 Tom 13-SEP-06 2413
5 Jane 17-APR-05 7654
6 James 18-JUL-04 5679
7 Jodd 20-JUL-03 5438
8 Joke 01-JAN-02 8765
9 Jack 29-AUG-01 7896
I'm not not able to understand this query.
After running inner query it will always gives me count of 8 after doing this it will go to where clause where it will pick salary which is higher than the outer query salary. How equal operator is working here in between inner and outer query and how comparison is happening.
Could any help me to understand how this query is working technically in back-end..?

SELECT *
FROM Employee Emp1
WHERE (N - 1) = (SELECT COUNT(DISTINCT(Emp2.orig_salary))
FROM Employee Emp2 <--- cartesian product with same table
WHERE emp2.orig_salary > emp1.orig_salary) <---- but do the cartesian product only if line of salary of emp 2 is greater than the current line of Emp1 'salary
e.g assume there are only 3 lines in the table:
ID Name Birth Orig_Salary
2 John 15-JUL-97 2341
3 Joe 25-JAN-86 4321
4 Tom 13-SEP-06 5413
the main query will look at the first line --> 2 John 15-JUL-97 2341 <---, and subquery will return 2 because the salaries 4321 (emp2.orig_salary) and 5413 (emp2.orig_salary) are greater than 2341 (emp1.orig_salary)
the main query will then look at the second line --> 3 Joe 25-JAN-86 4321 <---, and subquery will return 1 because the salaries 5413 (emp2.orig_salary) is greater than 2341 (emp1.orig_salary)
when i say subquery, it is the
=(SELECT COUNT(DISTINCT(Emp2.orig_salary))
FROM Employee Emp2 <--- cartesian product with same table
WHERE emp2.orig_salary > emp1.orig_salary)
and the main query is
SELECT *
FROM Employee Emp1
WHERE
the returned value from the subquery is then compare to the where condition n-1, if the condition is satisfied, then it retrieves the line.

There is no need to understand that query. The correct formulation is:
SELECT Emp1.*
FROM (SELECT Emp1.*, DENSE_RANK() OVER (ORDER BY Emp2.orig_salary) as seqnum
FROM Employee Emp1
) Emp1
WHERE seqnum = <n>;
This gives the details for the employees. If you just want the salary:
SELECT orig_salary
FROM (SELECT Emp1.*, DENSE_RANK() OVER (ORDER BY Emp2.orig_salary) as seqnum
FROM Employee Emp1
) Emp1
WHERE seqnum = <n> AND rownum = 1;
I should note that a simpler version of this is:
select distinct orig_salary
from employees
order by orig_salary desc
offset <n - 1>
fetch first 1 row only;
The use of a correlated subquery for this is a pleasant anachronism from the days when relational databases were not as powerful as they are now. It is of historical interest.

Related

SQL: finding the maximum average grouped by an ID

Consider following dataset:
id
name
mgr_id
salary
bonus
1
Paul
1
68000
10000
2
Lucas
2
29000
null
3
Max
1
50000
20000
4
Zack
2
30000
null
I now want to find the manager who pays his subordinates the highest average salary plus bonus. A manager is someone who is present in of the mgr_id cells. So in this example Paul and Lucas are managers because their id is present in the mgr_id column of themselves and Max for Paul and Zack for Lucas.
Basically I want MAX(AVG(salary + bonus)) and then grouped by the mgr_id. How can I do that?
I am using SQLite.
My expected output in this example would be simply the employee name 'Paul' because he has 2 subordinates (himself and Max) and pays them more than the other manager Lucas.
SELECT
mrg_id
, pay_avg
FROM
(
SELECT mrg_id
, AVG(salary + COALESCE(bonus,0)) pay_avg
FROM <table>
GROUP
BY mrg_id
) q
ORDER
BY pay_avg
desc
LIMIT 1
select top 1 t1.mgr_id,AVG((t1.salary)+(t1.bonus)) as tot_sal
from #tbl_emps as t1
group by t1.mgr_id
order by AVG((t1.salary)+(t1.bonus)) desc

Query to find least fifth salaried employee [duplicate]

This question already has answers here:
Select second most minimum value in Oracle
(3 answers)
Closed 4 years ago.
EMPID NAME DEPTID SALARY
---------- ------------------------------------------ --
101 surendra 201 1000
102 narendra 202 2000
103 rajesh 203 3000
104 ramesh 203 2000
105 hanumanth 202 10000
a) Write a Query to find least 5th (Least salary in 5th position from
least salary in the order) salaried employee?
b) Query to find the highest earning employee in each department
a) Write a Query to find least 5th (Least salary in 5th position from least salary in the order) salaried employee?
SELECT EMPID,NAME,DEPTID,SALARY
FROM
(
SELECT EMPID,NAME,DEPTID,SALARY, DENSE_RANK() OVER (ORDER BY SALARY) AS RN
FROM Table1
)
WHERE RN=5
b) Query to find the highest earning employee in each department
SELECT EMPID,NAME,DEPTID,SALARY
FROM
(
SELECT EMPID,NAME,DEPTID,SALARY,
DENSE_RANK() OVER (PARTITION BY DEPTID ORDER BY SALARY DESC) AS RN
FROM Table1
)
WHERE RN=1
Demo
http://sqlfiddle.com/#!4/63ce0/12
Let's assume we have a table named EmployeeSalary which has 3 columns:
Id
Name
Salary
Salary might be same for multiple employee according to the following table data
Id Name Salary
----------
6 Belalo 74
1 Karim 100
5 dIPU 100
4 Satter 102
9 Kiron 120
10 Rash 120
11 Harun 130
13 Baki 130
12 Munshi 132
2 Rahim 500
7 Kaif 987
8 Sony 987
3 Belal 4000
Now the query will be
SELECT A.Salary
FROM
(
SELECT DISTINCT Salary,
DENSE_RANK() OVER (ORDER BY Salary) AS Ranks
FROM [dbo].[EmployeeSalary]
) A
WHERE A.Ranks=5

Second Highest Salary without subquery

EmployeeID EmployeeName Department Salary
----------- --------------- --------------- ---------
1 Nisha Finance 40000.00
2 John Finance 25000.00
3 NEo Finance 25000.00
4 Dan Finance 15000.00
5 Jstin IT 80000.00
6 Amy IT 50000.00
I want to get the second highest Salary which is 50000.00 without using subquery?
Try below query, it will work.
select max(e1.salary) from Employee e1,Employee e2 where e1.salary<e2.salary;
Using limit and offset (to skip highest salary)
In MySQL
select * from table order by Salary desc limit 1 offset 1
In SQL server
select * from table order by Salary desc offset 1 rows fetch next 1 row only
You can try with another Database here
http://sqlfiddle.com/#!9/15c32/1/0
Couldn't you just use LIMIT 1,1 (grab first result after first row). I come from the MySql side of things so the sql might have to be adjusted slightly for Sql Server.
SELECT Salary FROM table ORDER BY Salary DESC LIMIT 1,1
SELECT DISTINCT Salary
FROM TABLE
ORDER BY Salary DESC OFFSET 1 ROWS
FETCH NEXT 1 ROW ONLY
Test this query after adding your table name and column names
select MAX(country) as country from users where country < ( select MAX(country) as country from users where country < (SELECT MAX(country) from users ) );
You can use TOP keyword to fetch number of records from the database tables. for example
SELECT TOP 1 * FROM TABLE NAME

Comparison with results from sub-query in sqlite

Here is the code:
SELECT * FROM COMPANY WHERE SALARY > 40000;
4 Mark 25 Rich-Mond 65000.0
5 David 27 Texas 85000.0
6 Kim 22 South-Hall 45000.0
8 Kitos 31 90000.0
SELECT * FROM COMPANY
WHERE AGE < (SELECT AGE FROM COMPANY WHERE SALARY > 40000);
3 Teddy 23 Norway 20000.0
6 Kim 22 South-Hall 45000.0
7 James 24 Houston 10000.0
How does this work when there are multiple row returned from the sub-query? In this example I would expect the last query to produce employees younger than 22 (minimum from the sub-query), apparently it doesn't work that way.
Most databases will raise an error if the subquery does not return exactly one result. SQLite doesn't, but just uses the first returned row (or NULL) (there is an implied LIMIT 1).
The order of SELECT results is not guaranteed without an ORDER BY, so the result will be random.
If you want to use some specific record, you must ensure that you SELECT returns exactly that record, typically using MIN/MAX, or with ORDER BY:
SELECT ...
FROM Company
WHERE Age < (SELECT MIN(Age)
FROM Company
WHERE Salary > 40000);
SELECT ...
FROM Company
WHERE Age < (SELECT Age
FROM Company
WHERE Salary > 40000
ORDER BY Age
LIMIT 1);
It is also possible to use a correlated subquery, which can return a different result for each row in the outer query:
SELECT ...
FROM Company
WHERE Age < (SELECT Age
FROM Company AS C2
WHERE C2.ID = Company.ManagerID);

SQL query to find Nth highest salary

I am referring to following query to find Nth highest salary of a employee.
select sal from emp t where &n = (select count(sal) from (select distinct sal
from emp) where t.sal<=sal);
One gentleman said this query works. Could someone please explain how equating a COUNT ( which really will be value between 1 to X where X is total distinct salaries) to &n produce this result ?
I am trying to understand how database handles this query internally and produces result ?
Thank you.
First, the query will return the nth lowest salary value. To return the nth highest salary value you must change t.sal <= sal to t.sal >= sal.
Next, this query works by first finding the distinct list of salary values as one derived table and then determines the number of employees that have a salary less than each one in this list. t.sal <= sal is taking the derived table (which most databases would require have an alias) and comparing each value against the outer emp table. It should be noted that this will return multiple rows in the case of a tie.
To manually trace the output, we need some inputs:
Alice | 200
Bob | 100
Charlie | 200
Danielle | 150
Select Distinct sal
From emp
Gives us
200
100
150
Now we analyze each row in the outer table
Alice - There are 3 distinct salary values less than or equal to 200
Bob - 1 rows <= 100
Charlie - 3 rows <= 200
Danielle - 2 row <= 150
Thus, for each salary value we get the following counts (and reordered by count):
Bob 1
Danielle 2
Charlie 3
Alice 3
The most important aspect that I think you are overlooking is that the outer emp table is correlated to the inner count calculation (which is why it is called a correlated subquery). I.e., for each row in the outer emp table, a new count is calculated for that row's salary via t.sal <= sal. Again, most database systems would require the inner most query to have an alias like so (note the As Z alias):
Select sal
From emp As t
Where &n = (
Select Count(Z.sal)
From (
Select Distinct sal
From emp
) As Z
Where t.sal <= Z.sal
)
select sal
from (
select sal,
dense_rank() over (order by sal desc) as rnk
) t
where rnk = 5;
Replace where rnk = 5 with whatever "nth" you want.
To get the nth highest salary value just put the value of 'N'.
Select Min(Salary) From (Select Top N * From Table_Name Order by Salary Desc);
SELECT TOP 1 salary
FROM (
SELECT DISTINCT TOP n salary
FROM employee
ORDER BY salary DESC) a
ORDER BY salary
where n > 1 (n is always
SELECT Max(Salary) as Salary
FROM employee
where Salary Not in
(SELECT TOP N Salary FROM employee ORDER BY Salary DESC)
where N is defined by you.
So let's say you have the following salaries in the table employee:
Here employeeID and Salary are the columns of employee table.
EmployeeID Salary
101 25,000
154 89,000
987 42,000
450 12,000
954 50,000
If we want to see the fourth-highest salary
Salary
25,000
Query return fourth highest salary.
In the database record data entries like
employ_id NAME salary
101 Henry 24000
102 Smith 24000
105 Roy 17000
106 Robbin 15000
702 Mac 2500
708 Bill 2100
709 Kane 2000
710 Ted 2000
here Some of employees having same salary then how to calculate nth (highest/lowest)salary
for the calculation of 3rd highest salary
select * from emloyees where salary in (select salary from (select rownum rank , salary from (select distinct salary from employees order by salary **desc**)) where rank =3;
ans = 15000
similarly to calculate 3rd lowest salary
Type same Query with a small change instead of desc type asc
select * from emloyees where salary in (select salary from (select rownum rank , salary from (select distinct salary from employees order by salary **asc**)) where rank =3;
Hope This will help you
Change nth highest salary value just put the value of 'N'
SELECT e1.EmployeeName, e1.EmployeeSalary from Employee e1
where N = (
select COUNT(e2.EmployeeSalary) from Employee e2 where e2.EmployeeSalary >= e1.EmployeeSalary)
There are so many ways to achieve this:-
1)
Select Top(1) sal from emp
where sal not in (select DISTINCT top(n-1) sal from emp order by sal desc)
2)
select salary
from (
select salary,
roe_number() over (order by salary ) as row from emp
) emp1
where row= n;
This query will not work if multiple rows have the same values one after another.
3)
select salary
from (
select salary,
dense_rank() over (order by salary ) as row from emp
) emp1
where row= n;
This will create a unique row number for all unique salary amounts.
4)
Select Min(sal) From
(Select DISTINCT Top n * From emp Order by sal Desc)as emp1;
5)
SELECT * FROM emp Emp1
WHERE (n-1) = (
SELECT COUNT(DISTINCT(Emp2.Sal))
FROM emp Emp2
WHERE Emp2.Sal > Emp1.Sal)
select salary
from (Select ROW_NUMBER() over(order by salary desc) as row ,salary from Employee)as temp
where row=2;
---2nd highest salary
n donated as nth number you want. like : i want second highest so my query will be
n=2
SELECT salary FROM Employee ORDER BY Salary DESC LIMIT 1,1
replace n with you number
SELECT salary FROM Employee ORDER BY Salary DESC LIMIT n-1,1
Query:
select
ename
,sal
,dense_rank() over (order by sal desc) ranking
from emp;
output:
ENAME SAL RANKING
KING 5000 1
FORD 3000 2
SCOTT 3000 2
JONES 2975 3
CLARK 2850 4
BLAKE 2850 4
ALLEN 1600 5
Wrap a filter around and pick out the Nth highest salary, say the 4th highest salary.
Query:
select *
from
(
select ename
,sal
,dense_rank() over (order by sal desc) ranking
from emp
)
where ranking = 4 -- Replace 4 with any value of N
output:
ENAME SAL RANKING
BLAKE 2850 4
CLARK 2850 4