Right outer JOIN in SQL - sql

I have to list all departments, which do not have any employees assigned to but I don't know how to solve this with a outer-join. The scheme of the database is:
My current statement is
SELECT DISTINCT d.department_name
FROM departments d
RIGHT OUTER JOIN employees e ON NOT e.department_id IS NULL;
but it doesn't work as it should.
My result is this:
It should look like this:
Does anybody know what's wrong?

You can right this as an outer left join like so, correlating on the department_id
SELECT d.department_name
FROM departments d
LEFT JOIN employees e ON e.department_id=d.department_Id
WHERE e.employee_id is null
Or a more intuitive version would be where there does not exist any employees for a department_id
SELECT d.department_name
FROM departments d
WHERE NOT EXISTS (SELECT * FROM employees e WHERE e.department_id=d.department_Id )

Related

SQL Oracle Missing keyword

create table EmployeesUK_9035
2 as
3 select e.employee_id,e.first_name || e.Last_name "Name",e.Salary,l.City,e.hire_date from employees e join locations l
4 where e.employee_id in(select e.employee_id from employees e join departments d on(e.department_id=d.department_id) join locations l on(d.location_id=l.location_id) where l.city='London');
...from employees e join locations l
4 where
You have missed out the ON section of the JOIN clause (in the main query, not the subquery).
This is the sort of bloomer which should be easy to spot. But because your code is all bunched up it's hard to diagnose. Laying code out nicely isn't just some neat-freakery on the part of experienced developers: readability is actually a feature of the code. Like this ...
create table EmployeesUK_9035
as
select e.employee_id,
e.first_name || e.Last_name "Name",
e.Salary,
l.City,
e.hire_date
from employees e
join locations l
where e.employee_id in (select e.employee_id
from employees e
join departments d
on (e.department_id=d.department_id)
join locations l
on (d.location_id=l.location_id)
where l.city = 'London')
;
See how easy it is to spot the missing line? You need an ON clause to join EMPLOYEES and LOCATIONS. However,given the join of the subquery you probably also need to include DEPARTMENTS in the main query because there appears to be no join between the two tables. In which case the query might simplify to
create table EmployeesUK_9035
as
select e.employee_id,
e.first_name || e.Last_name "Name",
e.Salary,
l.City,
e.hire_date
from employees e
join departments d
on (e.department_id=d.department_id)
join locations l
on (d.location_id=l.location_id)
where l.city = 'London'
;
Incidentally please don't use double-quotes and mixed-case for column-aliases when creating a table. You will have to use "Name" in double-quotes and the exact same case every time you reference it, which is a pain because Oracle code is generally case insensitive; that is, all Oracle identifiers are in upper-case by default but case doesn't matter provided we don't wrap the identifiers in double-quotes.
JOIN should have the ON (to show what you're joining those tables on), while yours doesn't.
I set ON 1 = 1, but you should use columns from EMPLOYEES and LOCATIONS tables.
CREATE TABLE EmployeesUK_9035
AS
SELECT e.employee_id,
e.first_name || e.Last_name "Name",
e.Salary,
l.City,
e.hire_date
FROM employees e JOIN locations l
ON 1 = 1 --> this
WHERE e.employee_id IN (SELECT e.employee_id
FROM employees e
JOIN departments d
ON (e.department_id = d.department_id)
JOIN locations l
ON (d.location_id = l.location_id)
WHERE l.city = 'London');

SQL-HR Schema, Retrieving the Dept.Names,managers and employees per dept

Hello guys and thank you in advance for your time and help.
So I am trying to get a list of the Department names their manager name and the total number of employees per department.
My code so far looks like this:
select d.department_name,e.first_name,e.last_name
from employees e, departments d
where e.department_id = d.department_id and d.manager_id=e.employee_id
group by d.department_name,e.first_name,e.last_name
order by d.department_name;
which produces the list of the manager per department,but I am still short of the count of employees per department. Any ideas?
You need to use the COUNT function. Try this:
select d.department_name,e.first_name,e.last_name,count(e.employee_id) as `TotalNoOfEmployees`
from employees e JOIN departments d
ON e.department_id = d.department_id and d.manager_id=e.employee_id
group by d.department_name,e.first_name,e.last_name
order by d.department_name;
Also try not to use the old way of Joining the tables ie, comma separated JOINS.
After a lot of experimentation I got it. Posting it in case somebody might find it useful someday:
select distinct d.department_name,
(select e.first_name||', '||e.last_name from employees e
where d.department_id=e.department_id and
d.manager_id=e.employee_id)as "manager_name",
( select count( employee_id ) from employees e
where d.department_id=e.department_id ) as "total_no_of_employees"
from employees e
join departments d on d.department_id=e.department_id
order by d.department_name;
Try this:
select emp.manager_id, mgr.first_name, mgr.last_name, dept.department_name, count(emp.employee_id)
from hr.employees emp
join hr.employees mgr
on emp.manager_id = mgr.employee_id
join hr.departments dept
on mgr.department_id = dept.department_id
group by emp.manager_id, mgr.first_name, mgr.last_name, dept.department_name
order by department_name

SQL group functions using joins

Problem:
Create a list of department names, the manager id,
manager name (employee last name) of that department, and the average salary in each
department.
SELECT d.department_name, d.manager_id, AVG(e.salary)
FROM employees e
INNER JOIN departments d ON (e.department_id = d.department_id)
GROUP BY d.department_name, d.manager_id;
And it works nice, but when I add the e.last_name, I get all the last names from employees table.
I do believe the answer to be out here and not quite far, although out of my reach at this point.
In order to pull the name of the manager, you need to join employees again, this time on d.manager_id:
SELECT d.department_name, d.manager_id, m.name, AVG(e.salary)
FROM employees e
INNER JOIN departments d ON (e.department_id = d.department_id)
LEFT OUTER JOIN employees m ON (m.employee_id = d.manager_id)
GROUP BY d.department_name, d.manager_id, m.name;
The kind of join (inner or outer) is not essential here, because you group by d.manager_id.
It looks like you need to join d.manager_id to employees again to get the managers last_name:
SELECT d.department_name, d.manager_id, e2.last_name, AVG(e.salary)
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id
INNER JOIN employees e2 ON d.manager_id = e2.employee_id
GROUP BY d.department_name, d.manager_id, e2.last_name

Join 3 tables and Group

I am stuck here working on a homework and this is what I have got.
Instruction is: Display department name, city and number of different jobs in each department.
tables employees (has job_id and department_id), deptos (has location_id, department_id but no job ids), locations (has location_id and city)
I need to include all cities even the ones without employees
What I was trying to do...
select d.department_name, l.city, count (distinct e.job_id)
from employees e
join deptos d on (e.department_id=d.department_id)
join locations l on (d.location_id=l.location_id)
group by d.department_name
locations can have data missing in other tables, so right join or you start from it and use left joins. You also need to group by city. Tried to do minimum changes to OP query.
select d.department_name, l.city, count(distinct e.job_id)
from employees e
join deptos d on (e.department_id=d.department_id)
right join locations l on (d.location_id=l.location_id)
group by d.department_name, l.city
SQL Fiddle to test with
You need to use a OUTER JOIN to accomplish this... like the below. You do not necessarily have to use the keyword outer as it is implied, just remember the the difference between using LEFT and RIGHT joins there is a post on that here. Example below
LEFT JOIN vs. LEFT OUTER JOIN in SQL Server
select d.department_name, l.city, count (distinct e.job_id)
from locations l
left outer join deptos d on (e.department_id=d.department_id)
left outer join employees e on (d.location_id=l.location_id)
group by d.department_name
SELECT locations.city, deptos.department_name,
Count(DISTINCT employees.job_id) AS DiffJobsDeptCount
FROM employees
RIGHT JOIN (deptos
RIGHT JOIN locations
ON deptos.location_id = locations.location_id)
ON employees.department_id = deptos.department_id
GROUP BY locations.city, deptos.department_name

Oracle SQL: ON Clause

SELECT e.employee_id, e.last_name, d.department_id, d.location_id
FROM employees e JOIN departments d
ON (e.department_id=d.department_id);
What exactly does the ON clause do? I'm confused on why e.department_id and d.department_id doesn't cause an error? Doesn't e represent the employees table and d represent the department table? So how can you use e.department_id if department_id is not in the employees table? I'm extremely confused about the purpose of the ON clause.
The ON clause is part of the JOIN syntax and it is used to identify how the tables should be joined to each other, in other words what columns relate the tables to each other.
In your case you are joining the tables on the e.department_id and the d.department_id.
The e is the alias for employees table and the d is the alias for the departments table.
Your current query is performing an INNER JOIN which will return only those rows that are matching in both tables.
If you want to return all employees even if there is no departments associated with an employee row, then you will want to use a LEFT JOIN:
SELECT e.employee_id, e.last_name, d.department_id, d.location_id
FROM employees e
LEFT JOIN departments d
ON e.department_id=d.department_id;
Not sure if it helps you to understand, but it's possible (though not recommended) to re-write this very query with implicit inner join in a form of WHERE clause:
SELECT e.employee_id, e.last_name, d.department_id, d.location_id
FROM employees e, departments d
WHERE (e.department_id=d.department_id);