Task with nested subqueries in SQL - sql

Using tables HR.DEPARTMENTS and HR.EMPLOYEES, create a list of departments that have employees named John.
Here is an example of the employees and departments table:
EMPLOYEE_ID FIRST_NAME LAST_NAME EMAIL PHONE_NUMBER HIRE_DATE JOB_ID SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
100 Steven King SKING 515.123.4567 17-JUN-03 AD_PRES 24000 - - 90
DEPARTMENT_ID DEPARTMENT_NAME MANAGER_ID LOCATION_ID
10 Administration 200 1700
i tried like this:
select department_id from HR.EMPLOYEES, HR.DEPARTMENTS
where 'John' = (select first_name from hr.employees)
How can I rewrite the query so that it works correctly?

I would use exists logic here rather than a join:
SELECT DEPARTMENT_ID
FROM HR.DEPARTMENTS d
WHERE EXISTS (
SELECT 1
FROM HR.EMPLOYEES e
WHERE e.DEPARTMENT_ID = d.DEPARTMENT_ID AND
e.FIRST_NAME = 'John'
);

We can use an IN clause here:
SELECT department_id, department_name
FROM hr.departments
WHERE department_id IN (
SELECT department_id
FROM hr.employees
WHERE first_name = 'John');
A JOIN is of course possible here, but should not be necessary because we don't want to apply further conditions here or fetch other data from the employees table.
It's enough to know John works in this department.
A side note: Your task to "create a list of departments" is very likely not correctly done by selecting the id only. So I selected also the department_name in the query above. And I assume it would be even better and correct to select the name only instead of the id and name.

select department_id from HR.EMPLOYEES WHERE first_name = 'Steven';
This should work. You don't need a JOIN.
If you want to ensure that the department_id exists in the DEPARTMENTS table, you can add a foreign key constraint on the DEPARTMENT_ID column of the table EMPLOYEES.

Related

somebody explain to me how this query works step by step?

I don't yet understand this SQL statement:
select FIRST_NAME
from EMPLOYEES e
where DEP_ID != (select DEP_ID
from EMPLOYEES
where e.MANAGER_ID = EMPLOYEE_ID);
I would write your query as:
select e.FIRST_NAME
from EMPLOYEES e
where e.DEP_ID <> (select e2.DEP_ID
from EMPLOYEES e2
where e.MANAGER_ID = e2.EMPLOYEE_ID
);
This does not functionally change the query but it qualifies all column references and uses <> which is the traditional SQL operator for not equals.
What this query is doing is returning all employees whose department is not the same as their managers department.
How does it do this? The subquery is a correlated subquery. For each row in employees the subquery returns the department id of the manager.
The where clause then checks whether or not it matches the employee's manager.
This subquery will get the Manager's departments.
select DEP_ID from EMPLOYEES where e.MANAGER_ID = EMPLOYEE_ID
So the main query will just get the employees that not managers.
select FIRST_NAME from EMPLOYEES e where DEP_ID != (Managers dept_ID)
It's finding the employees who are not under a particular manager.
Let's see the inner part first:
select DEP_ID from EMPLOYEES where e.MANAGER_ID = EMPLOYEE_ID
This will fetch the department under particular manager
Now the outer part:
select FIRST_NAME from EMPLOYEES e where DEP_ID != <Departments under particular manager>
Now the result will the list of employees's first name not under that manager

How to join two SELECT statements operating on the same column on a single table with different conditions?

I am trying complete the following exercise
Create a query that has the employee name, supervisor name, and employee salary for each employee who works in the 'Research' department
Which operates on the following schema:
https://scontent-lht6-1.xx.fbcdn.net/v/t34.0-12/23140228_10214571052854224_1441212020_n.png?oh=15f361ec2679373f2cfeb427dd5b6978&oe=59F9593B
I have developed the following query which works somewhat, but does not match the rows accordingly so I end up with a result consisting of the employee names and salaries, with separate rows for the manager names. My query is as follows:
CREATE VIEW research AS
SELECT NULL as Fname, NULL as Lname, NULL as Salary, Lname as Manager from EMPLOYEE
WHERE Ssn IN (SELECT Superssn from EMPLOYEE WHERE Dno = (SELECT Dnumber from DEPARTMENT WHERE Dname = 'Research'))
UNION
SELECT Fname, Lname, Salary, Null as Manager FROM EMPLOYEE
WHERE Dno = (SELECT Dnumber from DEPARTMENT WHERE Dname = 'Research');
Can anyone see what is wrong with this? Am I going the right way about it by using the UNION command?
Thank you.
It appears this is what you're trying to accomplish.
select
emp.FName as EmployeeFName
,emp.LName as EmployeeLName
,sup.FName as SupervisorFName
,sup.LName as SupervisorLName
,emp.Salary as Salary
from
Employee emp
inner join Department dept
on emp.dno = dept.dnumber
inner join Employee sup
on emp.SuperSSN = sup.SSN
where
dept.Name = 'Research'
No, you don't want UNION for this.
Why do you have super_ssn on EMPLOYEE and also mgr_ssn on DEPARTMENT? Isn't that redundant?
Anyway, here's another way to do it.
select fname, lname, salary,
(select lname from employee e where e.ssn = employee.superssn) manager
from employee
where dno = (SELECT Dnumber from DEPARTMENT WHERE Dname = 'Research');

How to solve this query in SQL?

I have the following two relations:
EMP(ENO, ENAME, JOB, DATEJOB, SAL, DNO)
DEPT(DNO, DNAME, DIR)
EMP is a relation of the employees with their number ENO, their names ENAME, their job titles JOB, the dates when they get hired, their salary SAL, and the department number they are working on DNO (forgein key which references DNO in DEPT).
DEPT is a relation of the department with the number of each department DNO, the name of the department DNAME, the director of the department DIR (forgein key which references ENO).
My question is:
Write the following query in SQL.
Find the names of the employees that have the same job and the same director as 'Joe'.
My attempt was:
SELECT ENAME
FROM EMP, DEPT
WHERE EMP.DNO = DEPT.DNO
AND (DIR, JOB) IN (
SELECT DIR, JOB
FROM EMP, DEPT
WHERE ENAME = 'Joe'
AND EMP.DEPT = DEPT.DNO
)
AND ENO NOT IN (
SELECT ENO
FROM EMP, DEPT
WHERE ENAME = 'Joe'
AND EMP.DEPT = DEPT.DNO
)
I found the solution of this problem but I couldn't agree of it.
This is what I found:
SELECT ENAME
FROM EMP, DEPT
WHERE ENAME <> 'Joe'
AND EMP.DNO = DEPT.DNO
AND (DIR, JOB) = (
SELECT DIR, JOB
FROM EMP, DEPT
WHERE ENAME = 'Joe'
AND EMP.DEPT = DEPT.DNO
)
The thing is, we have to not consider 'Joe' in the result. But which 'Joe'?
It looks like there's a potential for a "director" to head multiple departments. At least, the information model doesn't seem to be anything to restrict that (i.e. no unique constraint on DIR)
Presumably, we identify employee 'Joe' by finding the tuples(s) in EMP with ENAME attribute equal to 'Joe'.
And presumably, we would identify Joe's "director" by getting the value of the DIR attribute from the DEPT relation.
If we wanted employees in the "same department" as Joe, we could just use the value of the DNO attribute,... but the requirement says "same director". So, just in case the same director heads multiple departments, we'll get all the departments headed by that director.
Then, it's a simple matter of getting all of the employees in those departments, and check for a "job" that matches Joe's "job".
SELECT e.ENAME
FROM EMP j
JOIN DEPT i
ON i.DNO = j.DNO
JOIN DEPT d
ON d.DIR = i.DIR
JOIN EMP e
ON e.DNO = d.DNO
AND e.JOB = j.JOB
WHERE j.ENAME = 'Joe'
Again, if we wanted only the employees in the "same department" as Joe, we could dispense with one of those references to DEPT. The result from this would be different, if Joe's director heads another department, and there's an employee in that other department has the same job... that employee would be excluded from this query:
SELECT e.ENAME
FROM EMP j
JOIN DEPT i
ON i.DNO = j.DNO
-- JOIN DEPT d
-- ON d.DIR = i.DIR
JOIN EMP e
-- ON e.DNO = d.DNO
ON e.DNO = i.DNO
AND e.JOB = j.JOB
WHERE j.ENAME = 'Joe'
If there's a requirement to exclude Joe from the resultset, then we could add another predicate to the WHERE clause. If we don't assume that ENAME can't have a NULL value...
AND ( e.ENAME IS NULL OR e.ENAME <> 'Joe')
You're correct in that the second solution is wrong. If there are two 'Joe's it won't work right. That's why you should exclude based on the unique ENO instead of the non-unique name. The first query won't work for the same reason. In order to be certain, you can't select either just by names or titles or departments, because those can be duplicate. We have three Chris programmers in our department.
Also, that join syntax is obsolete because it can cause confusion to the database in certain circumstances. Please see http://www.w3schools.com/sql/sql_join_inner.asp for an explanation of the current syntax.
The comma style of join you are using has been obsolete for a long time. I think the below is what you're after. The idea is to join a table to its self. This is done by giving the table aliases- source and twin here.
SELECT twin.ENAME
FROM EMP AS source
JOIN EMP AS twin ON twin.DNO = source.DNO AND twin.JOB = source.JOB
WHERE source.ENAME = 'Joe' AND source.ENO <> target.ENO

group by expression not working properly?

My code works fine for the below query:
CREATE TABLE employee ( employee_id INTEGER, manager_id INTEGER, first_name VARCHAR2(10) NOT NULL, last_name VARCHAR2(10) NOT NULL, title VARCHAR2(20), salary NUMBER(6, 0) );
CREATE TABLE manager( manager_id INTEGER NOT NULL, manager_dept VARCHAR2(20) NOT NULL, first_name VARCHAR2(30) NOT NULL, last_name VARCHAR2(30) NOT NULL ) Here are my tables
SELECT
DISTINCT E.EMPLOYEE_ID, M.MANAGER_ID, E.FIRST_NAME,
E.LAST_NAME, CONNECT_BY_ISLEAF, CONNECT_BY_ISCYCLE, level
FROM EMPLOYEE E
LEFT OUTER JOIN MANAGER M
ON E.MANAGER_ID=M.MANAGER_ID
WHERE m.manager_id=10
start with e.employee_id >0
connect by NOCYCLE m.manager_id=prior e.employee_id
GROUP BY
E.EMPLOYEE_ID, M.MANAGER_ID, E.FIRST_NAME,
E.LAST_NAME, CONNECT_BY_ISLEAF, CONNECT_BY_ISCYCLE,LEVEL
but i want my result set to grouped by only on employee_id and not all fields
When i use this query below then an error generates "NOT A GROUP BY EXPRESSION"
SELECT
DISTINCT E.EMPLOYEE_ID, M.MANAGER_ID, E.FIRST_NAME,
E.LAST_NAME, CONNECT_BY_ISLEAF, CONNECT_BY_ISCYCLE, level
FROM EMPLOYEE E
LEFT OUTER JOIN MANAGER M
ON E.MANAGER_ID=M.MANAGER_ID
WHERE m.manager_id=10
start with e.employee_id >0
connect by NOCYCLE m.manager_id=prior e.employee_id
GROUP BY
E.EMPLOYEE_ID
Whats wrong with this query??
I assume your employee ID is unique, so by grouping by it, you're grouping by everything else in the query as well. But Oracle doesn't know that. If you were grouping by employee ID only, and you had two employees having the same id, one with last name "Smith" and one with last name "Miller", which one would you like to see? It's either Smith or Miller, as you have only one row of data, so the database doesn't know what to do.
That's why you always have to group by every column that's not aggregated (using SUM, MAX, MIN, or one of the other functions).
You could omit the columns from your result set and the group by, then put the whole query into a subquery, with the outer query selecting the remaining columns from a join of the subquery and the employee table. But trust me, you don't really want to do that, as that version would be much uglier to read and understand than your current query.

find the link in tables sql exercise

so I'm stuck on this question where it says:
write a query to retrieve a list of ALL departments in alphabetical order containing the columns DEPARTMENT_ID , DEPARTMENT_NAME , LAST_NAME , FIRST_NAME where last_name and first_name are the name of the Manager of the Department wherever there is one.
I'm have the HR database using the departments, employees table what i have written so far is:
select department_id, department_name, e.last_name, e.first_name
from departments d, employees e
where e.department_id=d.department_id
and d.department_id=e.department_id
and d.manager_id=e.manager_id
having department_name = '%Manager%';
yet i can't figure it out, any tips will help thanks!
A having clause relates to a group by. Where you have no group by, there is no meaning for a having clause.
You just need your join to get the record in the employees table for the manager.
select department_id, department_name, e.last_name, e.first_name
from departments d, employees e
where d.manager_id=e.id
Better is to use the newer join syntax,
select dept.department_id, dept.department_name, emp.last_name, emp.first_name
from departments dept
inner join employees emp on dept.manager_id = emp.id
You don't need conditions for e.department_id=d.department_id and d.department_id=e.department_id, (for one thing these are redundant, so you would only need one if they were needed) because the employees.department_id field refers to the department the employee is in, and what you want is the manager employee record for the department. The manager employee record for the department is represented as the foreign key to the primary key of the employee table.
this might help you...
`select e.first_name,e.last_name,d.department_id ,d.department_name from employees e,departmets d where d.manager_id=e.employee_id order by d.department_name;`