Why is this query displaying all the records? - sql

I have a query:
SELECT emp.empno , emp.ename , emp.job , emp.sal , dept.dname , dept.loc
FROM emp ,
dept
WHERE emp.ename = 'SMITH';
Please tell me why this is displaying all the Records , as i am expecting only one record ?
EMPNO ENAME JOB SAL DNAME LOC
---------- ---------- --------- ---------- -------------- -------------
7369 SMITH CLERK 800 ACCOUNTING NEW YORK
7369 SMITH CLERK 800 RESEARCH DALLAS
7369 SMITH CLERK 800 SALES CHICAGO
7369 SMITH CLERK 800 OPERATIONS BOSTON
7369 SMITH CLERK 800 CREDIT

The reason is because your query lacks JOIN criteria to link the two tables, so the result will be a cartesian product. Every EMP record will have a copy of every row in the DEPT table...
Your query uses ANSI-89 join syntax, which requires the criteria to be in the WHERE clause:
SELECT e.empno, e.ename, e.job, e.sal, d.dname, d.loc
FROM EMP e,
DEPT d
WHERE d.deptno = e.deptno
AND e.ename = 'SMITH'
But it would be preferable to use the ANSI-92 format:
SELECT e.empno, e.ename, e.job, e.sal, d.dname, d.loc
FROM EMP e
JOIN DEPT d ON d.deptno = e.deptno
WHERE e.ename = 'SMITH'

You need to join the tables, not select from each. The DB doesn't know the relation to emp and dept without a join.
Try:
select emp.empno , emp.ename , emp.job , emp.sal , dept.dname , dept.loc from emp inner
join dept on emp.deptno = dept.deptno where
emp.ename = 'SMITH';

Because you have not specified how to join emp and dept, and so have a Cartesian product (all possible combinations).
Try:
select emp.empno , emp.ename , emp.job , emp.sal , dept.dname , dept.loc
from emp
join dept on dept.deptno = emp.deptno
where emp.ename = 'SMITH';

It is because of your FROM emp , dept clause. I expect that 'SMITH' only belongs in one department and you really need to do a JOIN instead.

Because this is the result of a cross-join between these two tables (emp, dept). You are missing join condition, i.e.
where dept.deptno = emp.deptno and emp.ename = 'SMITH';

You need to join your emp and dept tables, as you are currently getting 1 row for each dept as there is no restriction applied to that table.
There is probably an emp.deptid column on the emp table, or some other joining table in the database.

Related

Name of department, Name of Manager, Number of employees who have salaries above average of the department

I want help with this question
provide a select statement that shows:
Name of department, Name of Manager, Number of employees who have salaries
above average of the department.
The table which we used the basic table in Scott and tiger ( emp, dept ) I try this code :
select d.dname , count (e.deptno) no_emp
from emp e, dept d
where e.deptno=d.deptno
and
e.sal >( select avg(sal) sal
from emp
where m.deptno=e.deptno
Group by m.deptno)
Group by e.deptno,d.dname
And I haven’t completed answer the name of manger doesn’t appear:
Dname
No_emp
ACCOUNTING
1
RESEARCH
3
SALES
2
I try also this code :
select d.dname, count(e.deptno) no_emp, e.ename mgr_dept
from emp e, dept d
where e.deptno = d.deptno
and e.ename in
(select ename
from emp
where job=‘MANAGER’ )
And e.sal >
(select avg(sal) sal
from emp
where m.deptno = e.deptno
Group by m.deptno)
Group by e.deptno, d.dname, e.ename
The result does not true:
DNAME
NO_EMP
MGR_DEPT
RESEARCH
1
JONES
SALES
1
BLAKE
Here's 2 methods
1) Join to a sub-query that calculates the employees with above average salary.
SELECT
dep.dname as department
, mgr.ename as manager
, depstat.above_average_salary
FROM DEPT dep
LEFT JOIN EMP mgr
ON mgr.deptno = dep.deptno
AND mgr.job = 'MANAGER'
JOIN (
SELECT deptno, COUNT(empno) as above_average_salary
FROM EMP e1
WHERE sal > (SELECT AVG(sal)
FROM EMP e2
WHERE e2.deptno = e1.deptno)
GROUP BY deptno
) depstat ON depstat.deptno = dep.deptno
ORDER BY dep.dname
DEPARTMENT | MANAGER | ABOVE_AVERAGE_SALARY
:--------- | :------ | -------------------:
ACCOUNTING | CLARK | 1
RESEARCH | JONES | 3
SALES | BLAKE | 2
2) Using conditional aggregation
SELECT
dep.dname as department
, MAX(CASE WHEN emp.job = 'MANAGER'
THEN emp.ename END) as manager
, COUNT(CASE WHEN emp.sal > depstat.avg_sal
THEN emp.empno END) as above_average_salary
FROM DEPT dep
LEFT JOIN EMP emp
ON emp.deptno = dep.deptno
JOIN (
SELECT deptno, AVG(sal) as avg_sal
FROM EMP
GROUP BY deptno
) depstat ON depstat.deptno = dep.deptno
GROUP BY dep.deptno, dep.dname
ORDER BY dep.dname
DEPARTMENT | MANAGER | ABOVE_AVERAGE_SALARY
:--------- | :------ | -------------------:
ACCOUNTING | CLARK | 1
RESEARCH | JONES | 3
SALES | BLAKE | 2
Demo on db<>fiddle here
There's a difference though.
The first method will show every manager.
The second method assumes that there's only 1 manager per department.

ORDER BY with DISTINCT gives ORA-01791: not a SELECTed expression

I trying to use oracle order by with select statement but it causes an Exception:
ORA-01791: not a SELECTed expression.
select distinct usermenu.menuname
from usermenu, userpermission
where userpermission.menuno = usermenu.menuno
and userpermission.userno = 1
order by userpermission.menuno;
When there's DISTINCT or an aggregate function in the SELECT statement's column list, ORDER BY a column which isn't part of the SELECT column list won't work.
Here's an example, based on Scott's schema.
This works OK, although D.LOC isn't selected:
SQL> select d.dname, e.ename
2 from dept d join emp e on e.deptno = d.deptno
3 order by d.loc;
DNAME ENAME
-------------- ----------
SALES BLAKE
SALES TURNER
SALES ALLEN
SALES MARTIN
SALES WARD
SALES JAMES
RESEARCH SCOTT
RESEARCH JONES
RESEARCH SMITH
RESEARCH ADAMS
RESEARCH FORD
ACCOUNTING KING
ACCOUNTING MILLER
ACCOUNTING CLARK
14 rows selected.
Now, add DISTINCT - basically, that's what you have:
SQL> select distinct d.dname, e.ename
2 from dept d join emp e on e.deptno = d.deptno
3 order by d.loc;
order by d.loc
*
ERROR at line 3:
ORA-01791: not a SELECTed expression
The same goes for aggregate functions, such as COUNT:
SQL> select d.dname, e.ename, count(*)
2 from dept d join emp e on e.deptno = d.deptno
3 group by d.dname, e.ename
4 order by d.loc;
order by d.loc
*
ERROR at line 4:
ORA-00979: not a GROUP BY expression
SQL>
So, what to do? Order by something else. Alternatively, use the current query as an inline view, join it with the table that contains the column you'd want to order the result by and it'll work:
SQL> select x.dname, x.ename
2 from (select distinct d.dname, e.ename
3 from dept d join emp e on e.deptno = d.deptno
4 ) x
5 join dept d1 on d1.dname = x.dname
6 order by d1.loc;
DNAME ENAME
-------------- ----------
SALES TURNER
SALES JAMES
SALES BLAKE
SALES WARD
SALES MARTIN
SALES ALLEN
RESEARCH SMITH
RESEARCH FORD
RESEARCH ADAMS
RESEARCH SCOTT
RESEARCH JONES
ACCOUNTING MILLER
ACCOUNTING KING
ACCOUNTING CLARK
14 rows selected.
SQL>

find emp_names,max,min salary and number of employees on each department?

I use oracle 11g , so i have 2 tables(employees,departments):
desc employees: desc departments
EMPLOYEE_ID DEPARTMENT_ID
FIRST_NAME DEPARTMENT_NAME
LAST_NAME MANAGER_ID
EMAIL LOCATION_ID
PHONE_NUMBER
HIRE_DATE
JOB_ID
SALARY
COMMISSION_PCT
MANAGER_ID
DEPARTMENT_ID
and i want to get
employee_name,emp_names,emp_salary,dep_id,dep_names,max salary on each
dep , and min salary on each dep , and number of employees on each
department .
so i do this qouery:
select FIRST_NAME,DEPARTMENT_ID,max(SALARY),min(SALARY),count(EMPLOYEE_ID)
from employees join departments on employees.department_id = departments.departm
ent_id group by first_name,department_id;
but its give an error:
ERROR at line 1: ORA-00918: column ambiguously defined
however does my sql query right ?
I don't have your tables so I created views out of Scott's ones, to simulate what you have.
SQL> create or replace view employees as
2 select empno employee_id,
3 ename last_name,
4 deptno department_id,
5 sal salary
6 from emp;
View created.
SQL> create or replace view departments as
2 select deptno department_id,
3 dname department_name
4 from dept;
View created.
SQL>
Here's how I understood the question: list of employees per department should be separated from the rest (minimums, maximums, counts).
So: list of employees:
SQL> select d.department_name, e.last_name
2 from departments d join employees e on d.department_id = e.department_id
3 order by d.department_name;
DEPARTMENT_NAM LAST_NAME
-------------- ----------
ACCOUNTING CLARK
ACCOUNTING KING
ACCOUNTING MILLER
RESEARCH JONES
RESEARCH FORD
RESEARCH ADAMS
RESEARCH SMITH
RESEARCH SCOTT
SALES WARD
SALES TURNER
SALES ALLEN
SALES JAMES
SALES BLAKE
SALES MARTIN
14 rows selected.
Aggregates: outer join for departments that don't have any employees:
SQL> select d.department_name,
2 min(e.salary) min_sal,
3 max(e.salary) max_sal,
4 count(e.employee_id) cnt_emp
5 from departments d left join employees e on d.department_id = e.department_id
6 group by d.department_name
7 order by d.department_name;
DEPARTMENT_NAM MIN_SAL MAX_SAL CNT_EMP
-------------- ---------- ---------- ----------
ACCOUNTING 1300 5000 3
OPERATIONS 0
RESEARCH 800 3000 5
SALES 950 2850 6
LISTAGG allows you to list all employees per department in the same statement, though; see line 5. I, somehow, doubt that you learnt about that function yet (as you struggle with such a problem).
SQL> select d.department_name,
2 min(e.salary) min_sal,
3 max(e.salary) max_sal,
4 count(e.employee_id) cnt_emp,
5 listagg(e.last_name, ', ') within group (order by e.last_name) employees
6 from departments d left join employees e on d.department_id = e.department_id
7 group by d.department_name
8 order by d.department_name;
DEPARTMENT_NAM MIN_SAL MAX_SAL CNT_EMP EMPLOYEES
-------------- ---------- ---------- ---------- -------------------------------------------
ACCOUNTING 1300 5000 3 CLARK, KING, MILLER
OPERATIONS 0
RESEARCH 800 3000 5 ADAMS, FORD, JONES, SCOTT, SMITH
SALES 950 2850 6 ALLEN, BLAKE, JAMES, MARTIN, TURNER, WARD
SQL>

select how many DEPTNO's exists for each LOC plus number of EMP's

I guess messed up the joins...
Single DEPT has many LOCations, every DEPT should have a sum of its EMPs. I need to show DISTINCT LOCs, number of LOCs per DEPT and sum of EMPS in each DEPT - without dividing the locations.
With tables DEPT & EMP like this:
SELECT DEPTNO, DNAME, LOC FROM DEPT;
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
50 NONE DALLAS
select ENAME, DEPTNO from EMP;
SMITH 20
ALLEN 30
WARD 30
JONES 20
MARTIN 30
BLAKE 30
CLARK 10
SCOTT 20
KING 10
TURNER 30
ADAMS 20
JAMES 30
FORD 20
MILLER 10
CURT 40
Can't properly add the below subquery into my WITH... clause below. Need to select how many DEPTNO's exists for each LOC plus give a number of EMP's in each DEPT like here (plus location number) - it should use 2 different kinds of summaries in:
select e.deptno, count(e.deptno) from emp e
group by e.deptno;
10 3
20 5
30 6
40 1
Here is what I did:
WITH workers_per_dept as
(SELECT
d.LOC LOC,
d.deptno DEPTNO,
count(e.empno) EMP_NUMBER
FROM dept d
LEFT OUTER JOIN emp e ON (e.deptno = d.deptno)
GROUP BY d.LOC,d.deptno
ORDER BY d.deptno)
select
d.LOC LOCATION,
count(d.LOC) LOCATIONS_PER_DEPT,
workers_per_dept.EMP_NUMBER
from DEPT d, workers_per_dept
WHERE d.LOC = workers_per_dept.LOC
GROUP BY d.LOC, workers_per_dept.EMP_NUMBER
ORDER BY 1;
I receive this (should be groupped by LOC with):
BOSTON 1 1
CHICAGO 1 6
DALLAS 2 0
DALLAS 2 5
NEW YORK 1 3
(result should have not repeated LOC's - 'DALLAS 2 0' should be skipped)
Here is the query. You need to group by location and count distinct occurrences of Dept's in each group:
select d.loc,
count(distinct d.deptno) depts,
count(e.ename) emps
from dept d
left join emp e on d.deptno = e.deptno
group by d.loc
Stupid me... but finally did it myself
it was so easy...
SELECT d.LOC LOCATION,
(select count(d.LOC) FROM DEPT l WHERE l.LOC=d.LOC) LOCS,
(select count(e.deptno) FROM EMP e WHERE e.DEPTNO = d.DEPTNO) EMPS
FROM DEPT d;
Thanks for help!!!

INNER JOIN condition not working

Suppose we have table as :
EMPNO ENAME DEPTNO
------ ------ ----------
7369 SMITH 20
7499 ALLEN 30
7654 MARTIN 30
7788 SCOTT 20
7839 KING 10
7900 JAMES 30
How can we find all those employees who work in the same deptno as of SCOTT ?
I tried as follows :
SELECT e.ename FROM employee e INNER JOIN employee m ON e.deptno=m.deptno;
, but the result isn't correct.
Try to add one more condition as below
SELECT e.ename
FROM employee e
INNER JOIN employee m ON e.deptno=m.deptno
AND m.ENAME = 'SCOTT'
WHERE m.ENAME <> 'SCOTT'; -- exclude scott
You can also try with a subquery
SELECT e.ename
FROM employee e
WHERE EXISTS
(
SELECT 1
FROM employee M
WHERE M.ENAME = 'SCOTT'
and E.deptno=M.deptno
)
AND m.ENAME <> 'SCOTT'; -- exclude scott;