Trouble understanding inner join - sql

Im trying to understand inner join correct use but im having trouble when I have to call more than 2 tables, im using oracle HR schema for tests, so for example im trying this query:
select emps.employee_id,
emps.first_name,
dep.department_name,
dep.department_id,
jh.job_id
from employees emps
inner join departments dep
on emps.department_id = dep.department_id
inner join job_history jh
on dep.department_id = jh.department_id;
which shows the following result:
I know its wrong because first its showing duplicate rows, and second if I run this query
select * from job_history where employee_id = 100;
It shows no results which means that employee 100 (steven) shouldnt be appearing in the results of the first query, I expect first query to show me the results of data that is on employees and also on department and also on job_history which have in common the department_id
HR (human resources schema):
Can anyone help me, what im missing, why it shows duplicate rows?

The job_history table has 3 foreign keys:
employee_id
job_id
department_id
Your INNER JOIN only joins on the DEPARTMENT_ID so you are matching an employee to the job history for any jobs that occurred for their department but not necessarily jobs specific to that employee. Instead, you probably want to join on either the employee_id or the combination of employee_id and department_id.
So, if you want the jobs history for that employee for any department:
select emps.employee_id,
emps.first_name,
dep.department_name,
dep.department_id,
jh.job_id
from employees emps
inner join departments dep
on ( emps.department_id = dep.department_id )
inner join job_history jh
on ( emps.employee_id = jh.employee_id );
Or, if you want the job history for that employee within that department:
select emps.employee_id,
emps.first_name,
dep.department_name,
dep.department_id,
jh.job_id
from employees emps
inner join departments dep
on ( emps.department_id = dep.department_id )
inner join job_history jh
on ( emps.employee_id = jh.employee_id
and emps.department_id = jh.department_id );

Related

Where clause and its order during join Operation

Was asked in an interview a traditional question of self join with manager and employee.
I was confused as interviewer asked me to display the columns as EmployeeName, Manager Name.
Please advice how does the conditions in where clause effects the selected columns. As I wasn't able to get the required order.
The trick here is that every manager is also an employee, so you can join the table on itself, and use one side of the join for the employee details and the other for the manager's details:
SELECT e.eployee_name AS "employee name", m.employee_name AS "manager name"
FROM employee e
JOIN employee m ON e.manager_id = m.employee_id
You can use the connect by query as following:
select employee_name, prior employee_name
from employees
connect by prior employee_id = manager_id
start with manager_id is null
If you want to use join then you must do outer join as following:
Select e.employee_name, m.employee_name
From employees e left join employees m
On e.employee_id = m.employee_id
Left outer join will make sure that all the employees will exists in the result as the employee who is the top manager will have null manager_id and inner join will exclude that employee from the result.
Cheers!!

SQLite Multiple Subqueries Logic

The problem is asking for one to write a query to find the names (first_name, last_name) of the employees who have a manager who works for a department based in the United States. Here is a link to the problem, to see the tables, https://www.w3resource.com/sqlite-exercises/sqlite-subquery-exercise-3.php.
For the subquery, I did a left join on the location id between the department and location tables then I selected 'US' for the country_id, and returned the manager_id
For the outer query, I chose the Employee table, selected manager_ids from sub-query list.
SELECT first_name, last_name
FROM Employees
WHERE manager_id IN (SELECT manager_id
FROM Departments d LEFT JOIN Locations l ON d.location_id = l.location_id
WHERE country_id = 'US')
ORDER BY first_name;
With my code, I do not get the correct answer, the same results as the result-set/output shown on the website.
There are three subqueries in total in the correct answer. I do not understand what the purpose of including the subquery involving the employees table (outermost subquery). I understand that is where I messed up but don't understand why.
SELECT first_name, last_name
FROM employees
WHERE manager_id IN
(SELECT employee_id
FROM employees
WHERE department_id IN
(SELECT department_id
FROM departments
WHERE location_id IN
(SELECT location_id
FROM locations
WHERE country_id='US')));
You need to join all the tables:
select e.first_name, e.last_name
from employees e
inner join employees m on m.employee_id = e.manager_id
inner join departments d on d.department_id = m.department_id
inner join locations l on l.location_id = d.location_id
where l.country_id='US'

Does this SQL statement look right?

I wondering is what I am doing right.
select distinct
Departments.Department_No, Departments.Department_Name
from
Departments
join
Employees on Departments.Department_No = Employees.Department_No
join
Jobs on Jobs.Job_ID = Employees.Job_ID
where
Departments.Department_No not in (select distinct Department_No
from Employees
where Employees.Job_ID like '%SA_REP%');
You want to display distinct values of Department Number and Department Name
You join Employees table with Department on Department Number
You join Jobs table with Employees on Job ID
You filter the result by excluding those Department Numbers of the entire Employee table that have a Job ID matching the pattern %SA_REP%
In my opinion you don't need
the join with the Jobs table
the join with the Employees table
you could maybe see if one of the other users' suggestions can bring performance improvement
SELECT DISTINCT departments.department_no,
departments.department_name
FROM departments
WHERE departments.department_no NOT IN (SELECT DISTINCT department_no
FROM employees
WHERE employees.job_id LIKE '%SA_REP%'
);
You could simply do this using NOT EXISTS instead of using a NOT IN subquery:
SELECT DISTINCT
d.Department_No
,d.Department_Name
FROM Departments d
JOIN Employees e ON d.Department_No = e.Department_No
WHERE NOT EXISTS
(select 1
from Employees e1
where e1.Job_ID like '%SA_REP%'
AND e1.Department_No = e.Department_No);
You can translate where condition without "in".
And you don't need to fetch date from "Jobs" - you don't use it
Select distinct Departments.Department_No, Departments.Department_Name
from Departments
Join Employees on Departments.Department_No = Employees.Department_No
where Employees.Job_ID not like '%SA_REP%';

SQL query errors and mistakes

I have an issue with a SQL query.
The question: show all the departments in which the max salary is bigger than 10000.
I am getting an output with this but it doesn't seem right.
My code:
SELECT
Department_Name, Max_Salary
FROM
Departments
INNER JOIN
Job_History ON Departments.department_id = Job_History.department_id
INNER JOIN
Jobs ON Job_History.job_id = jobs.job_id
WHERE
Max_Salary > 10000
Output:
DEPT_NAME | MAX_SALARY
------------------------
Accounting | 16,000
Sales | 12,080
Sales | 20,080
There is only one Sales department in the database.
Any help on why this is happening would be appreciated.
Likely, there are multiple rows in job_history that are related to 'Sales' Department.
The join operation is returning all matching rows.
To get a distinct list of Department_Name, you could add GROUP BY Department_name to the end of the query. You'll also want to use an aggregate function around the Max_Salary column in the select list... e.g. MAX(Max_Salary).
Best practice is to qualify all column references in the query. For a reader not familiar with the database schema, it's not clear whether Max_Salary is from the Job_History table, or the Job table. Also, the keyword INNER has no effect on the join operation, that keyword can be omitted.
--This works
SELECT d.department_name
, MAX(j.max_salary) AS max_salary
FROM Departments d
JOIN Job_History h
ON h.department_id = d.department_id
JOIN Jobs j
ON j.job_id = h.job_id
WHERE j.max_salary > 10000
GROUP BY d.department_name
I would prefer to comment, but I don't have a high enough reputation.
Can you try this and see what it brings for the ids.
Select Department_Name, Max_Salary,D.department_id,J.job_id
From Departments D
INNER JOIN Job_History J_H
ON D.department_id=J_H.department_id
INNER JOIN Jobs J
ON J_H.job_id=J.job_id
WHERE Max_Salary > 10000
Select d.department_name
, MAX(j.max_salary) AS max_salary
From Departments D
INNER JOIN Job_History J_H
ON D.department_id=J_H.department_id
INNER JOIN Jobs J
ON J_H.job_id=J.job_id
GROUP BY d.department_name
having max(j.max_salary)>10000

SQL for a many to many relationship using inner joins

I have the following many-to-many relationship between employees and workgroups:
employees table
-----------------
id
empgroups table
---------------
employee_id
workgroup_id
workorders table
----------------
workgroup_id
I'm trying to write SQL that will list all the workorders for an employee based on the workgroups that employee belongs to.
This is my attempt:
SELECT wonum, workgroup_id
FROM workorders
INNER JOIN employees
ON workorders.employee_id = employee_id
INNER JOIN empgroups
ON employees.employee.id = empgroups.employee_id
WHERE employee_id = 2
The error I get is:
ERROR: schema "employees" does not exist
Sorry - the employee has id not employee.id
Isn't this what you're looking for?
SELECT wonum, workgroup_id
FROM workorders
JOIN empgroups
ON empgroups.workgroup_id = workorders.workgroup_id
JOIN employees
ON employees.employee_id = empgroups.employee_id
WHERE employees.employee_id = 2
SELECT w.wonum, w.workgroup_id
FROM workorders w
JOIN empgroups e USING (workgroup_id)
WHERE e.employee_id = 2
The table employees is not needed at all for this query. USING shortens the syntax in this case. As do table aliases.
Try using this query instead:
SELECT * FROM empgroups
INNER JOIN employees
ON empgroups.empId = employees.id
INNER JOIN workorders
ON empgroups.woId = workorders.id
SqlFiddle