query to display the highest salaries of employees by age - sql

Can you help me? Need to get a list of the highest salaries of employee with the sample by age,first name and last name
Input:
Age FirstName LastName SAL
---------- ---------- ---------- ----------
30 Andy Donald 175
31 Petr Pess 295
30 John Jacky 453
31 Bob Bobby 385
29 Eric Rice 957
Answer should be
Age FirstName LastName SAL
---------- ---------- ---------- ----------
31 Bob Bobby 385
30 John Jacky 453
29 Eric Rice 957
Thanks in advance

If you have window/analytic functions available (you don't mention an RDBMS in the OP), you can do the following:
SELECT * FROM (
SELECT Age, FirstName, LastName, SAL
, DENSE_RANK() OVER (PARTITION BY Age ORDER BY SAL DESC) AS ranknum
FROM employees
) WHERE ranknum = 1
This will work even when two or more employees of the same age have the same salary - both will be returned. It will also allow you to get the 2nd highest salary, etc., if you want (just change ranknum = 1 to ranknum = 2, etc.).
Edit: FYI, this will work in Oracle, SQL Server, and PostgreSQL at least.

Get all employees for which there is no employee with the same age and with a higher salary:
SELECT *
FROM employees e1
WHERE NOT EXISTS (
SELECT 1
FROM employees e2
WHERE e1.age = e2.age
AND e1.sal < e2.sal
)
ORDER BY age DESC
If two employees have the same age and salary, both will be returned... This query will work on any database

If you are using MySQL, the following should work:
select * from
(select * from myTable order by age desc, sal desc) sq
group by age
(Although it won't return multiple rows for employees of the same age on the same salary.)

Related

Trying to find an Oracle query to find nth highest salary and among them one with highest experience

I need to find name of the person with 3rd highest salary
The table in question is as follows:
Name Salary Experience
-------------------------------
Den 11000 114
Gerald 11000 148
Ellen 11000 174
Eleni 10500 149
Clara 10500 162
Janette 10000 156
Peter 10000 150
Hermann 10000 204
Harrison 10000 169
I need to find name of the person having max experience and in the 3rd highest salary bracket.
So evidently, 3rd highest salary is 10000 and max experience among those having 3rd highest salary is Hermann with exp of 204.
I have query to find the 3rd highest salary:
select name, salary, experience
from sal s1
where 3 - 1 = (select count(distinct salary)
from sal s2
where s2.salary > s1.salary);
But this query returns 4 rows and I need to know how I can filter it even further in this same query to find Hermann with exp of 204.
Use the DENSE_RANK analytic function to find the 3rd highest salary and the ROW_NUMBER (or RANK or DENSE_RANK) analytic function with a PARTITION BY clause to find the highest experience per salary. This only requires a single table/index scan.
Oracle Setup:
CREATE TABLE table_name ( Name, Salary, Experience ) AS
SELECT 'Den', 11000, 114 FROM DUAL UNION ALL
SELECT 'Gerald', 11000, 148 FROM DUAL UNION ALL
SELECT 'Ellen', 11000, 174 FROM DUAL UNION ALL
SELECT 'Eleni', 10500, 149 FROM DUAL UNION ALL
SELECT 'Clara', 10500, 162 FROM DUAL UNION ALL
SELECT 'Janette', 10000, 156 FROM DUAL UNION ALL
SELECT 'Peter', 10000, 150 FROM DUAL UNION ALL
SELECT 'Hermann', 10000, 204 FROM DUAL UNION ALL
SELECT 'Harrison', 10000, 169 FROM DUAL
Query: If you want to find "the person having max experience in the 3rd highest salary bracket":
SELECT Name, Salary, Experience
FROM (
SELECT t.*,
DENSE_RANK() OVER ( ORDER BY Salary DESC ) AS s_rank,
ROW_NUMBER() OVER ( PARTITION BY Salary ORDER BY Experience DESC )
AS Exp_rownum
FROM table_name t
)
WHERE s_rank = 3
AND Exp_rownum = 1;
If you swap the ROW_NUMBER() analytic function for either RANK() or DENSE_RANK() then this will return multiple people if they are tied with the joint highest experience in the 3rd highest salary bracket.
Output:
NAME | SALARY | EXPERIENCE
:------ | -----: | ---------:
Hermann | 10000 | 204
Query: If you want to find "the person having max experience and (also) in the 3rd highest salary bracket":
Just take the query above and remove the PARTITION BY clause.
SELECT Name, Salary, Experience
FROM (
SELECT t.*,
DENSE_RANK() OVER ( ORDER BY Salary DESC ) AS s_rank,
ROW_NUMBER() OVER ( ORDER BY Experience DESC ) AS Exp_rownum
FROM table_name t
)
WHERE s_rank = 3
AND Exp_rownum = 1;
Output:
(Note: if Herman's experience was 173 then this would not return any rows as Ellen would have the highest experience but she would not be in the 3rd highest salary bracket and Herman would be in the 3rd highest salary bracket but would only have the 2nd highest experience.)
NAME | SALARY | EXPERIENCE
:------ | -----: | ---------:
Hermann | 10000 | 204
db<>fiddle here
This query makes use of ROWNUM and MAX to find the right row. In the innermost sub-query the max experience is retreived for each salary level, ordered by salary descending, and then in the outer sub-query row numbers are added and this is joined with the original table to find the correct row(s)
SELECT s.name, s.salary, s.experience
FROM sal s
JOIN (SELECT s2.*, ROWNUM rnum
FROM (SELECT salary, max(experience) AS m_exp
FROM sal
GROUP BY salary
ORDER BY salary DESC) s2) s3 ON s3.salary = s.salary AND
s3.m_exp = s.experience AND
rnum = 3
You don't query on the experience. So you've to add a where-clause:
select name, salary, experience
from sal s1
where 3 - 1 = (select count(distinct salary)
from sal s2
where s2.salary > s1.salary)
and experience = (select max(experience) from sal)
UPDATE
The alternative (max experience within 3rd highest salary) should be:
select name, salary, experience
from sal s1
where 3 - 1 = (select count(distinct salary)
from sal s2
where s2.salary > s1.salary)
and experience = (select max(experience) from sal s3
where 3 - 1 = (select count(distinct salary)
from sal s4
where s4.salary > s3.salary)
)

selecting a row using MIN or ROWNUM

I have a oracle table which is similar to the one below which stores people's lastname firstname and age. If last name is same people belong to same family.
LastName FirstName Age
===========================
1 miller charls 20
2 miller john 30
3 anderson peter 45
4 Bates andy 50
5 anderson gary 60
6 williams mark 15
I need to write a oracle sql query to
select youngest person from each family. output shd select rows 1,3,4 and 6
How do I do this ?
Another way, a bit shorter:
select lastname
, max(firstname) keep(dense_rank first order by age) as first_name
, max(age) keep(dense_rank first order by age) as age
from you_table_name
group by lastname
order by lastname
Result:
LASTNAME FIRST_NAME AGE
-------- ---------- ----------
Bates andy 50
anderson peter 45
miller charls 20
williams mark 15
And SQLFiddle Demo
DENSE_RANK() is a ranking function which generates sequential number and for ties the number generated is the same. I prefer to use DENSE_RANK() here considering that a family can have twins, etc.
SELECT Lastname, FirstName, Age
FROM
(
SELECT Lastname, FirstName, Age,
DENSE_RANK() OVER (PARTITION BY LastName ORDER BY Age) rn
FROM tableName
) a
WHERE a.rn = 1
SQLFiddle Demo
With Standard SQL I would do as this...
select *
from family f1
where (
select count(*)
from family f2
where
f2.lastname = f1.lastname
and
f2.age <= f1.age) <= 1
order by lastname;
This SQL gives you possibilities to pick x youngest/oldest in a family. Just modify the f2.age <= f1.age to e.g. f2.age >= f1.age, and the <= 1 to e.g. <=10 (to get top 10 youngest/oldest in a family).
SQLfiddle

SQL subqueries multiple value

I just need a little help about SQL queries
Here's the situation
ID FIRST_NAME LAST_NAME START_DAT END_DATE SALARY CITY DESCRIPTION
---- ---------- ---------- --------- --------- ---------- ---------- ---------------
01 Jason Martin 25-JUL-96 25-JUL-06 1234.56 Toronto Programmer
02 Alison Mathews 21-MAR-76 21-FEB-86 6661.78 Vancouver Tester
03 James Smith 12-DEC-78 15-MAR-90 6544.78 Vancouver Tester
04 Celia Rice 24-OCT-82 21-APR-99 2344.78 Vancouver Manager
05 Robert Black 15-JAN-84 08-AUG-98 2334.78 Vancouver Tester
06 Linda Green 30-JUL-87 04-JAN-96 4322.78 New York Tester
07 David Larry 31-DEC-90 12-FEB-98 7897.78 New York Manager
08 James Cat 17-SEP-96 15-APR-02 1232.78 Vancouver Tester
8 rows selected.
SQL> -- GROUP BY clause and AVG() function
SQL> SELECT city, AVG(salary)
2 FROM employee
3 GROUP BY city;
CITY AVG(SALARY)
---------- -----------
New York 6110.28
Toronto 1234.56
Vancouver 3823.78
The problem is I can't find a way to extract those names having higher salaries from each avg(salary) for city
Example:
Vancouver has avg(salary) of 3823.78 so I should get the name of 2 people: alison and james because they have higher salary than the avg(salary) of new york
For now I only go to this query but not working
select FIRST_NAME,SALARY,CITY
from employee
where SALARY > ( select avg(SALARY)
from employee
group by CITY
);
it tells me that subquery return more than 1 value
Hope someone can help me
Your query is returning more than one value. To restrict it to one value, you need a condition on city:
select FIRST_NAME,SALARY,CITY
from employee e
where SALARY > (select avg(SALARY)
from employee e2
where e2.city = e.city
group by CITY);
This is called a correlated subquery. You can also write it as a join, which is the syntax that I would use. The group by CITY is, strictly speaking, unnecessary, but I think it makes the intention of the subquery clearer.
You can rewrite this as a join by doing:
select e.FIRST_NAME, e.SALARY, e.CITY
from employee e join
(select city, avg(salary) as avgSalary
from employee
group by city
) ec
on e.city = ec.city
where e.salary > ec.avgSalary
Or, what would be my favorite way . . .
select e.FIRST_NAME, e.SALARY, e.CITY
from (select e.*,
avg(salary) over (partition by city) as avgSalary
employee e
) e
where e.salary > e.avgSalary

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

select dept names who have more than 2 employees whose salary is greater than 1000

How would do the following in SQL
"select dept names who have more than 2 employees whose salary is greater than 1000" ?
DeptId DeptName
------ --------
1 one
2 two
3 three
EmpId DeptId Salary
----- ------ ------
121 1 2000
122 1 2000
123 1 5000
124 1 4000
131 2 2000
132 2 6000
133 2 1000
134 2 1000
125 3 1000
126 3 20000
RESULT: one
How about something like this?
SELECT D.DeptName FROM
Department D WHERE (SELECT COUNT(*)
FROM Employee E
WHERE E.DeptID = D.DeptID AND
E.Salary > 1000) > 2
SELECT DEPTNAME
FROM(SELECT D.DEPTNAME,COUNT(EMPID) AS TOTEMP
FROM DEPT AS D,EMPLOYEE AS E
WHERE D.DEPTID=E.DEPTID AND SALARY>1000
GROUP BY D.DEPTID
)
WHERE TOTEMP>2;
select min(DEPARTMENT.DeptName) as deptname
from DEPARTMENT
inner join employee on
DEPARTMENT.DeptId = employee.DeptId
where Salary > 1000
group by (EmpId) having count(EmpId) > =2
hope this helps
select DeptName from DEPARTMENT inner join EMPLOYEE using (DeptId) where Salary>1000 group by DeptName having count(*)>2
select D.DeptName from [Department] D where D.DeptID in
(
select E.DeptId from [Employee] E
where E.Salary > 1000
group by E.DeptId
having count(*) > 2
)
select deptname from dept_1
where exists
(
SELECT DeptId,COUNT(*)
FROM emp_1
where salary>1000
and emp_1.deptid=dept_1.deptid
GROUP BY DeptId
having count(*)>2)
1:list name of all employee who earn more than RS.100000 in a year.
2:give the name of employee who earn heads the department where employee with employee I.D
My main advice would be to steer clear of the HAVING clause (see below):
WITH HighEarners AS
( SELECT EmpId, DeptId
FROM EMPLOYEE
WHERE Salary > 1000 ),
DeptmentHighEarnerTallies AS
( SELECT DeptId, COUNT(*) AS HighEarnerTally
FROM HighEarners
GROUP
BY DeptId )
SELECT DeptName
FROM DEPARTMENT NATURAL JOIN DeptmentHighEarnerTallies
WHERE HighEarnerTally > 2;
The very early SQL implementations lacked derived tables and HAVING was a workaround for one of its most obvious drawbacks (how to select on the result of a set function from the SELECT clause). Once derived tables had become a thing, the need for HAVING went away. Sadly, HAVING itself didn't go away (and never will) because nothing is ever removed from standard SQL. There is no need to learn HAVING and I encourage fledgling coders to avoid using this historical hangover.