What is wrong in the below query? - sql

I have written this query on oracle database.
Select salary from emp having salary < (SELECT MAX(SALARY) FROM EMP ));
http://sqlfiddle.com/#!4/47961/13
But it is not working .
Where am i wrong?

things to do,
use WHERE (use having when comparing with aggregated condition)
remove extra parenthesis,
eg.
Select salary
FROM emp
WHERE salary < (SELECT MAX(SALARY) FROM EMP );
SQLFiddle Demo

Two errors:
Use WHERE instead of HAVING.
Remove the extra parenthesis.
Try this:
SELECT salary
FROM emp
WHERE salary < (SELECT MAX(salary) FROM emp);
http://sqlfiddle.com/#!4/47961/17

Select salary from emp where salary < (SELECT MAX(SALARY) FROM EMP ));
you can apply having clause where you used group by , here there is no group by than just use where
The HAVING Clause
The HAVING clause was added to SQL because the WHERE keyword could not be used with aggregate functions.

Select salary from emp WHERE SALARY < (SELECT MAX(SALARY) FROM EMP );

Correct way using Having in Oracle:
SELECT sal FROM scott.emp
GROUP BY sal
HAVING sal < (SELECT MAX(SAL) FROM scott.EMP)
/
SELECT deptno, COUNT(*) total_emps_by_dept
FROM scott.emp
GROUP BY deptno
HAVING COUNT(*) > 1
/

Related

How to deal with the "missing right parenthesis " in Oracle 19c?

I have written a piece of code in Oracle database 19c to extract the salary of employees who earns more than the average salary of their respective departments but the query shows "missing right parenthesis". Can anybody help me with it, like where and what the error is all about?
select ename
from emp
where sal > (select round(avg(sal)) as avg_sal, deptno
from emp
group by deptno
order by 2);
You can use these queries to get job done.
select ename
from emp e1
where sal > (select round(avg(sal)) as avg_sal
from emp e2
where e2.deptno = e1.deptno
);
or
select e1.ename
from emp e1,
(
select round(avg(sal)) as avg_sal, deptno
from emp
group by deptno
) e2
where e1.deptno = e2.deptno
and e1.sal > avg_sal
;
Now the output of your subquery is 2 columns and multiple rows, which is against the business logic you described.
To gain the desired result you need to modify the query a bit:
remove the second column in subquery;
remove GROUP BY and ORDER BY clauses from the subquery.
Should be as follows:
SELECT ename FROM emp WHERE sal > (SELECT round(AVG(sal)) AS avg_sal FROM emp);
Now subquery returns only one values which is valuated with each salary in the main query and returns employees' names of ones, that have salary more that average.
The "missing right parenthesis" error is that the ORDER BY clause is not allowed in the sub-query so the SQL parser expects the query to end after the GROUP BY clause.
Once you fix that you get a further error that the sub-query will return multiple rows:
select ename
from emp
where sal > (select round(avg(sal)) as avg_sal, deptno
from emp
group by deptno);
Outputs a different error message:
ORA-00913: too many values
To fix that you need to restrict the sub-query to a single row and correlate the outer-query to the sub-query:
select ename
from emp e
where sal > (select round(avg(sal)) as avg_sal
from emp a
WHERE e.deptno = a.deptno);
Which, for the sample data:
CREATE TABLE emp (ename, sal, deptno) AS
SELECT 'Alice', 100, 1 FROM DUAL UNION ALL
SELECT 'Beryl', 200, 1 FROM DUAL UNION ALL
SELECT 'Carol', 300, 1 FROM DUAL UNION ALL
SELECT 'Debra', 100, 2 FROM DUAL UNION ALL
SELECT 'Ester', 200, 2 FROM DUAL;
Outputs:
ENAME
Carol
Ester
If you want to do it in a single table-scan then you can use analytic functions:
SELECT ename
FROM (
SELECT ename,
sal,
ROUND(AVG(sal) OVER (PARTITION BY deptno)) AS avg_sal
FROM emp
)
WHERE sal > avg_sal;
db<>fiddle here

What will be the SQL oracle query for finding out the maximum experience from hire date?

Have to find the most experienced employee.
select empno, ename,
from emp
where max(months_between(SYSDATE,hiredate))
My software is giving errors on sysdate, so could anyone please verify if this is correct.
Use NOT EXISTS:
select e.empno, e.ename
from emp e
where not exists (select 1 from emp where hiredate < e.hiredate)
or:
select empno, ename
from emp
where hiredate = (select min(hiredate) from emp)
or modify the WHERE clause of your query like this:
select empno, ename
from emp
where months_between(SYSDATE, hiredate) = (
select max(months_between(SYSDATE, hiredate))
from emp
)
You can use:
select e.*
from emp e
order by hiredate asc
fetch first 1 row only;
If you want duplicates, then add with ties.
The above works in Oracle 12C+. In earlier versions, you need a subquery:
select e.*
from (select e.*,
row_number() over (order by hiredate) as seqnum
from emp e
) e
where seqnum = 1;

sql subqueries and group by

I'm having an assignment for my sql class which i can't seem to figure out. This is the description of the select wanted:
Show all employees of which the salary is higher than the average of the colleagues in their department, only for the departments with at least 4 employees.
I've been able to find parts of the query like
select ename
from emp
where sal > any (select avg(sal)
from emp
group by
deptno);
to get the names of the employees which earn more than the avg.
or
select count(deptno)
from emp
group by
deptno having count(deptno) > 4;
to getthe number of employees in each department.
But somehow it doesn't work linking them together. Maybe someone can help me shine a light on this on.
Just put your second query in with an AND clause:
select ename
from emp
where sal > any (select avg(sal)
from emp
group by
deptno)
and deptno in (select deptno
from emp
group by
deptno having count(deptno) > 4);
You can use Having Clause in Conjunction with Group By
select ename
from emp
where sal > any (select avg(sal)
from emp
group by
deptno)
having count(*)>4;
select ename
from (
select deptno, count(deptno)
from emp
group by deptno
having count(deptno) > 4) valid_depts join emp ON emp.deptno=valid_depts.deptno
where sal > any (select avg(sal)
from emp
group deptno);

How can I select the record with the 2nd highest salary in database Oracle?

Suppose I have a table employee with id, user_name, salary. How can I select the record with the 2nd highest salary in Oracle?
I googled it, find this solution, is the following right?:
select sal from
(select rownum n,a.* from
( select distinct sal from emp order by sal desc) a)
where n = 2;
RANK and DENSE_RANK have already been suggested - depending on your requirements, you might also consider ROW_NUMBER():
select * from (
select e.*, row_number() over (order by sal desc) rn from emp e
)
where rn = 2;
The difference between RANK(), DENSE_RANK() and ROW_NUMBER() boils down to:
ROW_NUMBER() always generates a unique ranking; if the ORDER BY clause cannot distinguish between two rows, it will still give them different rankings (randomly)
RANK() and DENSE_RANK() will give the same ranking to rows that cannot be distinguished by the ORDER BY clause
DENSE_RANK() will always generate a contiguous sequence of ranks (1,2,3,...), whereas RANK() will leave gaps after two or more rows with the same rank (think "Olympic Games": if two athletes win the gold medal, there is no second place, only third)
So, if you only want one employee (even if there are several with the 2nd highest salary), I'd recommend ROW_NUMBER().
If you're using Oracle 8+, you can use the RANK() or DENSE_RANK() functions like so
SELECT *
FROM (
SELECT some_column,
rank() over (order by your_sort_column desc) as row_rank
) t
WHERE row_rank = 2;
This query works in SQL*PLUS to find out the 2nd Highest Salary -
SELECT * FROM EMP
WHERE SAL = (SELECT MAX(SAL) FROM EMP
WHERE SAL < (SELECT MAX(SAL) FROM EMP));
This is double sub-query.
I hope this helps you..
WITH records
AS
(
SELECT id, user_name, salary,
DENSE_RANK() OVER (PARTITION BY id ORDER BY salary DESC) rn
FROM tableName
)
SELECT id, user_name, salary
FROM records
WHERE rn = 2
DENSE_RANK()
You should use something like this:
SELECT *
FROM (select salary2.*, rownum rnum from
(select * from salary ORDER BY salary_amount DESC) salary2
where rownum <= 2 )
WHERE rnum >= 2;
select * from emp where sal=(select max(sal) from emp where sal<(select max(sal) from emp))
so in our emp table(default provided by oracle) here is the output
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
7698 BLAKE MANAGER 7839 01-MAY-81 3000 30
7788 SCOTT ANALYST 7566 19-APR-87 3000 20
7902 FORD ANALYST 7566 03-DEC-81 3000 20
or just you want 2nd maximum salary to be displayed
select max(sal) from emp where sal<(select max(sal) from emp)
MAX(SAL)
3000
select * FROM (
select EmployeeID, Salary
, dense_rank() over (order by Salary DESC) ranking
from Employee
)
WHERE ranking = 2;
dense_rank() is used for the salary has to be same.So it give the proper output instead of using rank().
select Max(Salary) as SecondHighestSalary from Employee where Salary not in
(select max(Salary) from Employee)
I would suggest following two ways to implement this in Oracle.
Using Sub-query:
select distinct SALARY
from EMPLOYEE e1
where 1=(select count(DISTINCT e2.SALARY) from EMPLOYEE e2 where
e2.SALARY>e1.SALARY);
This is very simple query to get required output. However, this query is quite slow as each salary in inner query is compared with all distinct salaries.
Using DENSE_RANK():
select distinct SALARY
from
(
select e1.*, DENSE_RANK () OVER (order by SALARY desc) as RN
from EMPLOYEE e
) E
where E.RN=2;
This is very efficient query. It works well with DENSE_RANK() which assigns consecutive ranks unlike RANK() which assigns next rank depending on row number which is like olympic medaling.
Difference between RANK() and DENSE_RANK():
https://oracle-base.com/articles/misc/rank-dense-rank-first-last-analytic-functions
I believe this will accomplish the same result, without a subquery or a ranking function:
SELECT *
FROM emp
ORDER BY sal DESC
LIMIT 1
OFFSET 2
This query helps me every time for problems like this. Replace N with position..
select *
from(
select *
from (select * from TABLE_NAME order by SALARY_COLUMN desc)
where rownum <=N
)
where SALARY_COLUMN <= all(
select SALARY_COLUMN
from (select * from TABLE_NAME order by SALARY_COLUMN desc)
where rownum <=N
);
select * from emp where sal = (
select sal from
(select rownum n,a.sal from
( select distinct sal from emp order by sal desc) a)
where n = 2);
This is more optimum, it suits all scenarios...
select max(Salary) from EmployeeTest where Salary < ( select max(Salary) from EmployeeTest ) ;
this will work for all DBs.
You can use two max function. Let's say get data of userid=10 and its 2nd highest salary from SALARY_TBL.
select max(salary) from SALARY_TBL
where
userid=10
salary <> (select max(salary) from SALARY_TBL where userid=10)
Replace N with your Highest Number
SELECT *
FROM Employee Emp1
WHERE (N-1) = (
SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary)
Explanation
The query above can be quite confusing if you have not seen anything like it before – the inner query is what’s called a correlated sub-query because the inner query (the subquery) uses a value from the outer query (in this case the Emp1 table) in it’s WHERE clause.
And Source
I have given the answer here
By the way I am flagging this Question as Duplicate.
Syntax it for Sql server
SELECT MAX(Salary) as 'Salary' from EmployeeDetails
where Salary NOT IN
(
SELECT TOP n-1 (SALARY) from EmployeeDetails ORDER BY Salary Desc
)
To get 2nd highest salary of employee then we need replace “n” with 2 our query like will be this
SELECT MAX(Salary) as 'Salary' from EmployeeDetails
where Salary NOT IN
(
SELECT TOP 1 (SALARY) from EmployeeDetails ORDER BY Salary Desc
)
3rd highest salary of employee
SELECT MAX(Salary) as 'Salary' from EmployeeDetails
where Salary NOT IN
(
SELECT TOP 2 (SALARY) from EmployeeDetails ORDER BY Salary Desc
)
SELECT * FROM EMP WHERE SAL=(SELECT MAX(SAL) FROM EMP WHERE SAL<(SELECT MAX(SAL) FROM EMP));
(OR)
SELECT ENAME ,SAL FROM EMP ORDER BY SAL DESC;
(OR)
SELECT * FROM(SELECT ENAME,SAL ,DENSE_RANK()
OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) R FROM EMP) WHERE R=2;
select salary from EmployeeDetails order by salary desc limit 1 offset (n-1).
If you want to find 2nd highest than replace n with that 2.

I want to display some columns of a table based on a subquery

I want to Display department number, names and salaries of employees who are earning max salary in their departments which are in the same table.
I am using oracle sql. The Table structure I am using is
Emp(Empno,Ename,Job,Salary,Deptno)
I have read about this and I think that this can be done by the use of correlated sub-queries. The query I fired was
select E1.Ename,E1.Ename,E1.Salary
from Emp E1
where E1.Empno=(
select Empno
from Emp E2
where Salary=(
select max(Salary)
from Emp
where Deptno=E1.Deptno
)
);
This gives an error saying "single-row subquery returns more than one row".
What am I doing wrong? What should do to correct it?
SELECT EmpNo, Ename,Job,Salary,Deptno
FROM
(
SELECT EmpNo, Ename,Job,Salary,Deptno,
DENSE_RANK() OVER (PARTITION BY DeptNo
ORDER BY Salary DESC ) rn
FROM Emp
) a
WHERE a.rn = 1
DENSE_RANK
or by using MAX
SELECT a.*
FROM Emp a
INNER JOIN
(
SELECT DeptNo, MAX(Salary) Max_sal
FROM Emp
GROUP BY DeptNo
) b ON a.DeptNo = b.DeptNo AND
a.Salary = b.Max_SAL