SQL Query with two WHERE conditions - sql

My task is:
To make a query which will get Employees, who earn the biggest salary for their working experience. In other words, the Employee who earns the biggest salary with the biggest experience.
As I consider, I need to make a query with two conditions:
select * from employee where salary in (select max(salary) from employee) and
hire_date in (select min(hire_date) from employee)

I think this was what you're trying to do:
select * from (
select *,
datediff(day,hire_date,getdate()) [Days_Worked],
dense_Rank() over(Partition by datediff(day,hire_date,getdate()) order by salary desc) [RN]
from employee
)a
where a.RN = 1
order by Days_Worked DESC
So that'll give you a list of employees with the highest salary against the employees that have worked the same number of days.
Just note that with dense rank if for example there are 2 employees that have worked 88 days and both earn $50000 (higher than anyone else) it will list both employees, use ROW_NUMBER() instead of DENSE_RANK() if you want to restrict examples like that to 1 employee.

If I get it correctly, this query solves your problem.
SELECT TOP 1 WITH TIES * FROM
employee
ORDER BY
hire_date ASC,
salary DESC

Related

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

Row_number function using directly

Is there any direct way of using row_number() function? I want to find 2 nd highest salary
SELECT DISTINCT id
,salary
,depid
,ROW_NUMBER() OVER (
PARTITION BY depid ORDER BY salary DESC
) AS rownum
FROM emp
WHERE rownum = 2;
It gives an error, However the below code works fine.
SELECT *
FROM (
SELECT DISTINCT id
,salary
,depid
,ROW_NUMBER() OVER (
PARTITION BY depid ORDER BY salary DESC
) AS rownum
FROM emp
) AS t
WHERE t.rownum = 2;
Is any way of directly using the row_number() function as in the first option which is giving the error?
You can not use the alias name of the same query as the condition for the where clause. You also can not use windowed queries as a passing condition in the where clause.
Here is a detailed explanation Why no windowed functions in where clauses?. It is so you need another query outside the inner query and needs to write sub-query.
You can get the Nth highest salary in SQL Server from the below query.
SELECT TOP 1 salary
FROM (
SELECT DISTINCT TOP N salary
FROM <YourTableNameHere>
ORDER BY salary DESC
) AS TEMP
ORDER BY salary
This query will give you the second highest salary ? No
SELECT id
,salary
,depid
from emp
ORDER BY salary DESC
OFFSET 1 ROWS
FETCH FIRST 1 ROWS ONLY;
Well actually, it will give you the salary that is on the second position when you order the salary's from highest to lowest... So if the highest is 100 and the second highest is 100 then you will get 100 as a result. To conclude this will return a row on the second place depending on the order by clause...
This next query will give you the second highest salary :
SELECT max(id)
, salary
, max(depid)
from emp
group by salary
ORDER BY salary DESC
OFFSET 1 ROWS
FETCH FIRST 1 ROWS ONLY;
But be aware, in case you have two employees from two different departments with the same salary then it will return you the one with the higher id and it will return the higher department id which can be incorrect.
And finally this will give you one employee that has a second largest salary with correct data:
SELECT id
, salary
, depid
from emp
where id = (SELECT max(id)
from emp
group by depid, salary
ORDER BY salary DESC
OFFSET 1 ROWS
FETCH FIRST 1 ROWS ONLY);
First, you want dense_rank(), not row_number() if you want the second highest value -- ties might get in the way otherwise.
You can use an arithmetic trick:
SELECT TOP (1) WITH TIES id, salary, depid
FROM emp
ORDER BY ABS(DENSE_RANK() over (PARTITION BY depid ORDER BY salary DESC) - 2)
The "-2" is an arithmetic trick to put the "second" values highest.
That said, I would stick with the subquery because the intent in clearer.
You could use a variation on the trick that uses a TOP 1 WITH TIES in combination with an ORDER BY ROW_NUMBER
SELECT TOP 1 WITH TIES
id,
salary,
depid
FROM emp
ORDER BY IIF(2 = ROW_NUMBER() OVER (PARTITION BY depid ORDER BY salary DESC), 1, 2)
But this trick does have the disadvantage that you can't sort it by something else.
Well, not unless you wrap it in a sub-query and sort the outer query.
A test on rextester here
I prefer to use dense_rank() instead of row_number() function with CTE (common table expression) for the scenario you have mentioned. CTE is modern, easy to use and have many cool features like it is memory resident, it can be used for DUI operations, it make code easy to understand etc.
To find Nth highest salary, the CTE look like
;with findnthsalary
as
(
select empid, deptid, salary,
dense_rank() over(partition by deptid order by salary desc) salrank
from
Employee
)
select distinct id, deptid, salary
from findnthsalary
where salrank = N
I used dense_rank() because if you use row_number() it will produce the wrong result in case multiple employees have the same salary in the same department.

Employee that has a higher salary than the AVERAGE of his department - optimized

We have only a table named EMPLOYEESALARY in our database with the 3 following columns:
Employee_ID, Employee_Salary, Department_ID
Now I have to SELECT every employee that has a higher salary than the AVERAGE of his department. How do I do that?
I know this is a repeat question but the best solution I found everywere was:
SELECT * from employee join (SELECT AVG(employee_salary) as sal, department_ID
FROM employee GROUP BY Department_ID) as t1
ON employee.department_ID = t1.department_ID
where employee.employee_salary > t1.sal
Can we optimize it further and do it without a subquery?
Reference:
SELECT every employee that has a higher salary than the AVERAGE of his department
Employees with higher salary than their department average?
Find Schema here, to test: SQL Fiddle
Can we do it without a subquery?
Not that I can think of. Had the condition been >= then the following would have worked
SELECT TOP 1 WITH TIES *
FROM employee
ORDER BY CASE
WHEN employee_salary >= AVG(employee_salary)
OVER (
PARTITION BY Department_ID) THEN 0
ELSE 1
END
But this is not an optimisation and it won't work correctly for the > condition if no employee has a salary greater than the average anyway (i.e. all employees in a department had the same salary)
Can we optimize it further?
You could shorten the syntax a bit with
WITH T AS
(
SELECT *,
AVG(employee_salary) OVER (PARTITION BY Department_ID) AS sal
FROM employee
)
SELECT *
FROM T
WHERE employee_salary > sal
but it still has to do much the same work.
Assuming suitable indexes on the base table already exist then the only way of avoiding some more of that work at SELECT time would be to pre-calculate the grouped SUM and COUNT_BIG in an indexed view grouped by Department_ID (to allow the average to be cheaply derived) .
A more optimal form is likely to be:
select e.*
from (select e.*, avg(employee_salary) over (partition by department_id) as avgs
from employee e
) e
where employee_salary > avgs;
This (as well as other versions) can use an index on employee(department_id, employee_salary). The final where probably should not use an index, because it is selecting lots of rows.

SQL query in Oracle and SQL server to get 3rd highest salary

In oracle will the below query works for getting 3rd highest salary.
select empname, salary
from (select empname,salary from employee order by salary desc)
where rownum==3
I have seen answers in other threads but they seem to be complicated. If above query works then it is simple solution for oracle
What will be the query for SQLServer?
I don't have Oracle and SQLServer software to try out these queries.
Please let me know
For SQL server the solution would be like this:
Select TOP 1 Salary as '3rd Highest Salary'
from (SELECT DISTINCT TOP 3 Salary from Employee ORDER BY Salary DESC)
a ORDER BY Salary ASC
Use Dense_Rank() ranking function in SQL SERVER to find the 3rd highest salary.
Row_number() returns the sequential number of a row within a partition of a result set, starting at 1 for the first row in each partition.The ORDER BY clause determines the sequence in which the rows are assigned their unique ROW_NUMBER
SELECT empname,
salary
FROM (SELECT Dense_Rank() OVER(ORDER BY salary DESC) rn,
empname,
salary
FROM employee) A
WHERE rn = 3
I did some exploration and found below link which explains the difference between row_number(), rank() and dense_rank(). From the below link I found dense_rank() is suitable answer for this question.
http://www.dwbiconcepts.com/tutorial/24-interview-questions/190-top-20-sql-interview-questions-with-answers.html
row_number() does not give expected results if two or more empolyees has same salary.
Below query works for both Oracle and SQL Server when tried on http://sqlfiddle.com/. The following query gives you the list of employees with third highest salary
SELECT empname, salary FROM (SELECT empname, salary, dense_rank() over(order by salary desc) dense_rank_by_sal
FROM EMPLOYEE ) A where dense_rank_by_sal=3;

SQL query to find third highest salary in company

I need to write a query that will return the third highest salaried employee in the company.
I was trying to accomplish this with subqueries, but could not get the answer. My attempts are below:
select Max(salary)
from employees
where Salary not in
(select Max(salary)
from employees
where Salary not in
(select Max(salary)
from employees));
My thought was that I could use 2 subqueries to elimitate the first and second highest salaries. Then I could simply select the MAX() salary that is remaining. Is this a good option, or is there a better way to achieve this?
The most simple way that should work in any database is to do following:
SELECT * FROM `employee` ORDER BY `salary` DESC LIMIT 1 OFFSET 2;
Which orders employees by salary and then tells db to return a single result (1 in LIMIT) counting from third row in result set (2 in OFFSET). It may be OFFSET 3 if your DB counts result rows from 1 and not from 0.
This example should work in MySQL and PostgreSQL.
Edit:
But there's a catch if you only want the 3rd highest DISTINCT salary. Than you should add the DISTINCT keyword.
In case of salary list: 100, 90, 90, 80, 70.
In the above query it will produce the 3rd highest salary which is 90. But if you mean the 3rd distinct which is 80 than you should use
SELECT DISTINCT `salary` FROM `employee` ORDER BY `salary` DESC LIMIT 1 OFFSET 2;
But there's a catch, this will return you only 1 column which is Salary, because in order to operate the distinction operation, DISTINCT can only operate on a specific set of columns.
This means we should add another wrapping query to extract the employees(There can be multiple) that matches that result. Thus I added LIMIT 1 at the end.
SELECT *
FROM `employee`
WHERE
`Salary` = (SELECT DISTINCT `Salary`
FROM `employee`
ORDER BY `salary` DESC
LIMIT 1 OFFSET 2
)
LIMIT 1;
Examples can be found HERE
You can get the third highest salary by using limit , by using TOP keyword and sub-query
TOP keyword
SELECT TOP 1 salary
FROM
(SELECT TOP 3 salary
FROM Table_Name
ORDER BY salary DESC) AS Comp
ORDER BY salary ASC
limit
SELECT salary
FROM Table_Name
ORDER BY salary DESC
LIMIT 2, 1
by subquery
SELECT salary
FROM
(SELECT salary
FROM Table_Name
ORDER BY salary DESC
LIMIT 3) AS Comp
ORDER BY salary
LIMIT 1;
I think anyone of these help you.
You may try (if MySQL):
SELECT salary FROM employee ORDER BY salary DESC LIMIT 2, 1;
This query returns one row after skipping two rows.
You may also want to return distinct salary. For example, if you have 20,20,10 and 5 then 5 is the third highest salary. To do so, add DISTINCT to the above query:
SELECT DISTINCT salary FROM employee ORDER BY salary DESC LIMIT 2, 1;
SELECT Max(salary)
FROM employee
WHERE salary < (SELECT Max(salary)
FROM employee
WHERE salary NOT IN(SELECT Max(salary)
FROM employee))
hope this helped you
If SQL Server this could work
SELECT TOP (1) * FROM
(SELECT TOP (3) salary FROM employees ORDER BY salary DESC) T
ORDER BY salary ASC
As for your number of subqueries question goes it depends on your language. Check this for more information
Is there a nesting limit for correlated subqueries in Oracle?
SELECT id
FROM tablename
ORDER BY id DESC
LIMIT 2 , 1
This is only for get 3rd highest value .
You may use this for all employee with 3rd highest salary:
SELECT * FROM `employee` WHERE salary = (
SELECT DISTINCT(`salary`) FROM `employee` ORDER BY `salary` DESC LIMIT 1 OFFSET 2
);
Some DBMS's don't allow you to run several nested queries. Here is a solution that only uses 1 nested query:
SELECT salary
FROM
(
SELECT salary
FROM employees
ORDER BY salary
LIMIT 3
) as TBL1
ORDER BY salary DESC
LIMIT 1;
It should give you the desired result. It first finds the 3 largest salaries, then selects the smallest of the three (or the third one if they are equal). Here is an SQLFiddle
I found a very good explanation in
http://www.programmerinterview.com/index.php/database-sql/find-nth-highest-salary-sql/
This query should give nth highest salary
SELECT *
FROM Employee Emp1
WHERE (N-1) = (
SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary)
SELECT MAX(salary) FROM employees GROUP BY salary ORDER BY salary DESC LIMIT 1 OFFSET 2;
SELECT * FROM employee ORDER BY salary DESC LIMIT 1 OFFSET 2;
You can use nested query to get that, like below one is explained for the third max salary. Every nested salary is giving you the highest one with the filtered where result and at the end it will return you exact 3rd highest salary irrespective of number of records for the same salary.
select * from users where salary < (select max(salary) from users where salary < (select max(salary) from users)) order by salary desc limit 1
Below query will give accurate answer. Follow and give me comments:
select top 1 salary from (
select DISTINCT top 3 salary from Table(table name) order by salary ) as comp
order by personid salary
you can get any order for salary with that:
select * from
(
select salary,row_Number() over (order by salary DESC ) RN
FROM employees
)s
where RN = 3
-- put RN equal to any number of orders.
--for your question put 3
You can find Nth highest salary by making use of just one single query which is very simple to understand:-
select salary from employees e1 where N-1=(select count(distinct
salary) from employees e2 where e2.salary>e1.salary);
Here Replace "N" with number(1,2,3,4,5...).This query work properly even when where salaries are duplicate. The simple idea behind this query is that the inner subquery
count how many salaries are greater then (N-1). When we get the count then the cursor will point to that row which is N and it simply returns the salary present in that row.
SELECT salary FROM employees e1
WHERE N-1 = (SELECT COUNT(DISTINCT salary) FROM employees e2
WHERE e2.salary > e1.salary)
Here, I have solved it with a correlated nested query. It is a generalized Query so if you want to print 4th, 5th, or any number of highest salary it will work perfectly even if there are any duplicate salaries.
So, what you have to do is simply change the N value here. So, in your case, it will be,
SELECT salary FROM employees e1
WHERE 3-1 = (SELECT COUNT(DISTINCT salary) FROM employees e2
WHERE e2.salary > e1.salary)
Note that the third highest salary may be the same the the first highest salary so your current approach wouldn't work.
I would do order the employees by salary and apply a LIMIT 3 at the end of the SQL query. You'll then have the top three of highest salaries and, thus, you also have the third highest salary (if there is one, a company may have two employees and then you wouldn't have a third highest salary).
For me this query work fine in Mysql
it will return third max salary from table
SELECT salary FROM users ORDER BY salary DESC LIMIT 1 OFFSET 2;
or
SELECT salary FROM users ORDER BY salary DESC LIMIT 2,1;
select min (salary) from Employee where Salary in (Select Top 3 Salary from Employee order by Salary desc)
SELECT TOP 1 BILL_AMT Bill_Amt FROM ( SELECT DISTINCT TOP 3 NH_BL_BILL.BILL_AMT FROM NH_BL_BILL ORDER BY BILL_AMT DESC) A
ORDER BY BILL_AMT ASC
SELECT DISTINCT MAX(salary) AS max
FROM STAFF
WHERE salary IN
(SELECT salary
FROM STAFF
WHERE salary<(SELECT MAX(salary) AS maxima
FROM STAFF
WHERE salary<
(SELECT MAX(salary) AS maxima
FROM STAFF))
GROUP BY salary);
I have tried other ways they are not right. This one works.
We can find the Top nth Salary with this Query.
WITH EMPCTE AS (
SELECT E.*, DENSE_RANK() OVER(ORDER BY SALARY DESC) AS DENSERANK
FROM EMPLOYEES E
)
SELECT * FROM EMPCTE WHERE DENSERANK=&NUM
for oracle it goes like this:
select salary from employee where rownnum<=3 order by salary desc
minus
select salary from employee where rownnum<=2 order by salary desc;
The SQL-Server implementation of this will be:
SELECT SALARY FROM EMPLOYEES OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY
This is a MYSQL query.
Explanation: The subquery returns top 3 salaries. From the returned result, we select the minimum salary, which is the 3rd highest salary.
SELECT MIN(Salary)
FROM (
SELECT Salary
FROM Employees
ORDER BY Salary DESC
LIMIT 3
) AS TopThreeSalary;
in Sql Query you can get nth highest salary
select * from(
select empname, sal, dense_rank()
over(order by sal desc)r from Employee)
where r=&n;
To find to the 2nd highest sal set n = 2
To find 3rd highest sal set n = 3 and so on.
This works fine with Oracle db.
select SAL from ( SELECT DISTINCT SAL FROM EMP ORDER BY SAL DESC FETCH FIRST 3 ROWS ONLY ) ORDER BY SAL ASC FETCH FIRST 1 ROWS ONLY
SELECT *
FROM maintable_B7E8K
order by Salary
desc limit 1 offset 2;
--Oracle SQL
with temp as (
select distinct salary from HR.EMPLOYEES
order by SALARY desc
)
select min(temp.salary) from temp
where rownum <= 3;
SELECT * FROM(
SELECT salary, DENSE_RANK()
OVER(ORDER BY salary DESC)r FROM Employee)
WHERE r=&n;
To find the 3rd highest salary set n = 3