Why are these 2 queries giving different outputs? - sql

Query no 1:-
SELECT COUNT(ENAME)
FROM EMP
WHERE
JOB IN 'MANAGER'
OR JOB IN 'ANALYST'
AND SAL IN (
SELECT SAL + NVL (COMM,0)
FROM EMP
WHERE SAL LIKE '%0')
GROUP BY JOB;
The Query 1 gives me the following output:-
COUNT(ENAME)
------------
3
2
Query no 2:-
SELECT COUNT(ENAME)
FROM EMP
WHERE
JOB = ANY (
SELECT JOB
FROM EMP
WHERE JOB IN ('MANAGER', 'ANALYST')
)
AND SAL IN (
SELECT SAL + NVL (COMM,0)
FROM EMP
WHERE SAL LIKE '%0'
)
GROUP BY JOB;
The Query 2 gives me the following output:-
COUNT(ENAME)
------------
2
2

Summary: The AND operator has higher precedence than the OR operator. To fix it, use brackets around the OR expression.
AND has higher precedence than OR so your first query is the equivalent of (with added brackets and indentation to emphasise the precedence):
SELECT COUNT(ENAME)
FROM EMP
WHERE JOB IN 'MANAGER'
OR ( JOB IN 'ANALYST'
AND SAL IN (
SELECT SAL + NVL (COMM,0)
FROM EMP
WHERE SAL LIKE '%0'
)
)
GROUP BY JOB;
So you are finding either: managers with any salary; or analysts whose salary equals the salary plus commission of any other employee.
Your second query is the equivalent of:
SELECT COUNT(ENAME)
FROM EMP
WHERE ( JOB IN 'MANAGER'
OR JOB IN 'ANALYST'
)
AND SAL IN (
SELECT SAL + NVL (COMM,0)
FROM EMP
WHERE SAL LIKE '%0'
)
GROUP BY JOB;
Which finds: any employee who is either a manager or an analyst and whose salary equals the salary plus commission of any other employee.
You could rewrite your first query to:
SELECT COUNT(ENAME)
FROM EMP
WHERE JOB IN ('MANAGER', 'ANALYST')
AND SAL IN (
SELECT SAL + NVL (COMM,0)
FROM EMP
WHERE SAL LIKE '%0'
)
GROUP BY JOB;

JOB IN 'MANAGER' OR ...
means all managers OR the next predicate
please put parentheses to achieve the expected result
JOB IN ('MANAGER', 'ANALYST')

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

using set operator query to find the result of the given questions

Using set operator display the DEPTNO,SUM(SAL) for each dept, JOB,SUM(SAL) for each Job and Total Salary.
Using Set Operator display the JOB and Deptno in employees working in deptno 20,10,30 in that order.
for first question my query is this:
select e.deptno,to_char(null),e.sum(sal),
from emp e
UNION
select d.deptno,d.job,d.sum(sal)
from emp d
group by deptno,job;
I have no idea how to do the second one.
SET opetator can be union,intersection,minus...
The phrasing of the first question is not 100% clear to me, but the query should be:
select deptno, '', sum(sal) from emp group by deptno
union
select deptno, job, sum(sal) from emp group by deptno, job
For the second question you can use UNION again. For example:
select job, deptno
from (
select job, deptno, 2 as o from emp where deptno = 10
union
select job, deptno, 1 from emp where deptno = 20
union
select job, deptno, 3 from emp where deptno = 30
) x
order by o

SQL Server 2014 Management Studio update query

I have a table Employee with those columns
empid, empname, job, hiredate, sal, comm, deptno
I want to verify if this is correct:
Number of employees in each department
How many people there are in each type of job in each department
Display the department and number of employees in department with fewer than 6 employees
Find the employee name and its salary who is earning maximum salary in dept 20
Here is what I have tried:
Query #1:
select DEPTNO, count(*) AS NO_OF_PERSONS
from EMP
group by DEPTNO;
Query #2:
select job, count(*) AS NO_OF_PERSONS
from EMP
group by job;
Query #3:
update EMPLOYEE
set sal = sal + 1000
where com > 2500;
And I am unable to do the 4th part.
I hope that below queries will help you.
no of employees in each dept?
SELECT DEPTNO,
count(*) AS NO_OF_PERSONS
FROM EMP
GROUP BY DEPTNO;
how many people are there in each type of job in each department?
SELECT job,
deptno,
count(*) AS NO_OF_PERSONS
FROM EMP
GROUP BY job,
deptno;
display the department and no of employees in department with fewer than 6 employee.
SELECT deptno,
count(*)
FROM emp
GROUP BY deptno
HAVING count(*) < 6;
find the employee name and its salary who is earning maximum salary in dept 20.
SELECT Max(salary_amount),
empid
FROM EMP
WHERE deptno = 20
GROUP BY empid;
You can start learning Basic SQL here
select e1.name, e1.sal
from EMP e1
where e1.DEPTNO = 20
and not exists(select *
from EMP e2
where e2.DEPTNO = 20
and e2.sal > e1.sal);

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 to display null value attributes?

This is the question:
Create a query to list all the employees who joined this organization before any clerks
were hired and who earn more than any manager.
This is what I have so far:
select ename
from emp
where hiredate<any(select hiredate from emp
where job='CLERK')
and job!='CLERK'
and sal>any(select sal from emp
where empno=super);
-But one of the employees don't have a supervisor (which is null) so it doesn't show any of the employees.
Something like this?
SELECT ename
FROM emp
WHERE hiredate < ANY (
SELECT hiredate
FROM emp
WHERE job = 'CLERK'
)
AND job <> 'CLERK'
AND sal > ANY (
SELECT sal
FROM emp
WHERE empno IN (
SELECT super
FROM emp
WHERE super IS NOT NULL
)
);
Is it a homework? If yes, should be labelled as such.