why query is showing 'invalid relational operator' - sql

select *
from employees
where department_id,salary in (
select department_id,max(salary)
from employees group by department_id
)

You want tuple comparison - you need to surround the tuple of columns on the left side of in with parentheses:
select *
from employees
where (department_id,salary) in (
select department_id, max(salary) from employees group by department_id
)
Note that this top-1-per-group query can be more efficiently phrased with window functions:
select *
from (
select e.*, rank() over(partition by department_id order by salary desc nulls last) rn
from employees e
) t
where rn = 1

Related

Analytic functions and means of window clause for calculating sum

I'm using Oracle and SQL Developer. I have downloaded HR schema and need to do some queries with it. Now I'm working with table Employees. As a user, I need the sum of salary of 3 employees with highest salary in each department. I have done query for defining 3 employees with highest salary in each department:
SELECT
*
FROM
(
SELECT
employee_id,
first_name
|| ' '
|| last_name,
department_id,
salary,
ROW_NUMBER()
OVER(PARTITION BY department_id
ORDER BY
salary DESC
--ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING
) result
FROM
employees
)
WHERE
result <= 3;
I need to use means of window clause. I have done something like this:
SELECT
department_id,
SUM(salary)
OVER (PARTITION BY department_id ORDER BY salary
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) total_sal
FROM
(
SELECT
employee_id,
first_name
|| ' '
|| last_name,
department_id,
salary,
ROW_NUMBER()
OVER(PARTITION BY department_id
ORDER BY
salary DESC
--ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING
) result
FROM
employees
)
WHERE
result <= 3;
Here is the result:
It has the necessary sum for 3 people in department and other unnnecessary results for 2 and so on. I need such result:
How can I modify my query to receive appropriate result (I need to use a window clause and analytic fuctions)?
You want aggregation rather than windowing in the outer query:
SELECT
department_id,
SUM(salary) total_sal
FROM
(
SELECT
employee_id,
first_name
|| ' '
|| last_name,
department_id,
salary,
ROW_NUMBER()
OVER(PARTITION BY department_id
ORDER BY
salary DESC
--ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING
) result
FROM
employees
) e
WHERE
result <= 3
GROUP BY department_id
I we were to do the same task with window functions only, then, starting from the existing query, we can either add another level of nesting of some sort, or use WITH TIES. Both pursue the same effect, which is to limit the results to one row per group.
The latter would look like:
SELECT
department_id,
SUM(salary) OVER(PARTITION BY department_id) total_sal
FROM (
SELECT e.*,
ROW_NUMBER() OVER(PARTITION BY department_id ORDER BY salary DESC) result
FROM employees e
) e
WHERE result <= 3
ORDER BY result FETCH FIRST ROW WITH TIES
While the former would phrase as:
SELECT department_id, total_sal
FROM (
SELECT e.*,
SUM(salary) OVER(PARTITION BY department_id) total_sal
FROM (
SELECT e.*,
ROW_NUMBER() OVER(PARTITION BY department_id ORDER BY salary DESC) result
FROM employees e
) e
WHERE result <= 3
) e
where result = 1

getting multiple records in second query

select max(salary)
from employees
group by department_id
select * from employees
where salary in (select max(salary)
from employees
group by department_id )
I think that you are looking for a correlated subquery:
select e.*
from employees e
where e.salary = (
select max(e1.salary)
from employees e1
where e1.department_id = e.department_id
)
This query gives you employees that have the greatest salary in their department (ties included).
For performance, consider an index on employees(department_id, salary).
You can use the analytical function as follows:
Ties included:
select * from
(select e.*, dense_rank() over (partition by e.department_id order by e.salary) as rn
from employees e)
where rn = 1
Ties excluded (one random record when ties)
select * from
(select e.*, row_number() over (partition by e.department_id order by e.salary) as rn
from employees e)
where rn = 1

Find Highest Salary of employs in each department in SQL

Result Should be the under lined rows in below image
You can use correlated subquery
select * from tablename t1 where salary =
(select max(salary) from tablename t2 where t1.deptname=t2.deptname)
use window function if support your dbms
select * from
(
select *, row_number() over(partition by department order sal desc) rn
from your_tab
) t where t.rn=1
select sal.empid,sal.name,t.department,t.sal from salary ,(select department,MAX(sal) as sal from salary group by dep)t
where sal.dep=t.dep and sal.sal=t.sal

Select all employees having high salary for each profession

I have this table. I want to select all employees in each profession with maximum salary.
I tried everything, but nothing seems to be working.
The below query results error.
SELECT * FROM Employee WHERE EmployeeID IN (
SELECT EmployeeID FROM Employee HAVING MAX(Salary) = Salary GROUP BY Profession)
You can use ROW_NUMBER window function
SELECT *
FROM (SELECT *,
Row_number()OVER (PARTITION BY Profession ORDER BY Salary DESC) rn
FROM Employee) a
WHERE rn = 1
Note : When there is a tie in maximum salary for a profession then this will return only one, if you need the tie records then use DENSE_RANK
SELECT *
FROM (SELECT *,
Dense_rank()OVER (PARTITION BY Profession ORDER BY Salary DESC) rn
FROM Employee) a
WHERE rn = 1
in case you want to fix your sub-query then(will return the tie records)
SELECT *
FROM Employee e1
WHERE Salary = (SELECT Max(Salary)
FROM Employee e2
WHERE e1.Profession = e2.Profession)
or
SELECT *
FROM Employee e1
WHERE EXISTS (SELECT 1
FROM Employee e2
WHERE e1.Profession = e2.Profession
HAVING Max(Salary) = e1.Salary)
SELECT *
FROM (
SELECT *
, ROW_NUMBER() OVER (PARTITION BY Profession ORDER BY Salary DESC) rn
FROM Employee
) x
WHERE x.rn = 1
Try this simple query !
SELECT
EmployeeID ,
EmployeeName ,
Profession ,
max(Salary) AS 'Salary'
FROM
Employee
GROUP BY
Profession
SELECT *
FROM employees
WHERE salary IN (SELECT MAX(salary)
FROM Employees
GROUP BY Profession)

Why query to find the 3rd highest salary is not working?

I have a employee table having salary column.
Now I can find maximum salary by.
select max(salary) from emp;
And 2nd highest salary by
select max(salary) from emp where salary not in (select max(salary)from emp);
Now I am trying to find 3rd highest salary using this two..
select max(salary) from emp where salary not in
(
select max(salary)from emp,
select max(salary) from emp where salary not in (select max(salary)from emp)
);
Here I am getting error.
ORA-00903: invalid table name :
Why am I wrong?
try this,
WHERE ( n ) here pass which you want 2nd highest or third highest pass as WHERE ( 2 ) for second highest and WHERE (3) for third highest.
SELECT *
FROM emp Emp1
WHERE ( n ) = (
SELECT COUNT( DISTINCT ( Emp2.salary ) )
FROM emp Emp2
WHERE Emp2.salary >= Emp1.salary
)
you can use this also
Select TOP 1 salary as '3rd Highest Salary'
from (SELECT DISTINCT TOP 3 salary from emp ORDER BY salary DESC)
a ORDER BY salary ASC
Try this simpler method:
select *
From(
SELECT ROW_NUMBER() OVER (ORDER BY salary DESC)
AS MaxSal,salary from emp
)x where MaxSal=2
See example in SQL Fiddle.
Now you just have to replace 2 with n to find the nth highest Maximum Salary.
This is what i would use dense_rank for, this also could give the same salaries, the same "rank".
select
*
from
(SELECT
SALARY,
dense_rank () over (order by SALARY desc) as RANK
from
EMP)
where
RANK = 3
Try with ROW_NUMBER analytical function.
SELECT *
FROM(
SELECT s.*, row_number() OVER (ORDER BY sal DESC) rownumber
FROM emp s
)
WHERE rownumber = 3;
This should work
Select * from
( select e.*, row_number()
OVER ( ORDER BY salary DESC )
MaxSal from emp e)
MaxSal=3
You may use this
SELECT * FROM table_name ORDER BY salary DESC LIMIT 2,1
It's objecting to the SELECT at the beginning of the line:
SELECT MAX(salary) FROM emp WHERE salary NOT IN (SELECT MAX(salary)FROM emp)
The IN list can contain a list of values or a query which returns a list of values, not a list queries. When it saw this SELECT it was parsing the previous FROM clause an though you where giving it a coma separated list of tables, hence the TABLE NAME error.
To run the query your way you could have written:
WITH
EMP AS
( SELECT 30000 SALARY FROM DUAL
UNION ALL
SELECT 30000 SALARY FROM DUAL
UNION ALL
SELECT 20000 SALARY FROM DUAL
UNION ALL
SELECT 10000 SALARY FROM DUAL
)
SELECT MAX(salary) FROM emp WHERE salary NOT IN
(
SELECT MAX(salary)FROM emp
UNION ALL
SELECT MAX(salary) FROM emp WHERE salary NOT IN (SELECT MAX(salary)FROM emp)
);
However #Tom's answer gives a nice standard solution with the same result as you. I'd like to offer the following alternative (but use #Tom's):
SELECT DISTINCT salary
FROM emp
ORDER BY salary DESC
OFFSET 2 ROWS FETCH FIRST ROW ONLY