Does this SQL statement look right? - sql

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%';

Related

Trouble understanding inner join

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 );

Subquery using 3 Tables SQL

I'm trying to display the last name of the lowest paid employees from each city. The city column falls under a table titled LOCATIONS while employee information(salary, last name) falls under EMPLOYEES. Both of these tables are related share no common table, so I have to rely on a third table, DEPARTMENTS to connect the two as DEPARTMENTS contains a department_id that it shares with EMPLOYEES as well as a LOCATION_ID that it shares with LOCATIONS. This is what I have so far, but I'm having trouble with this as I've mostly worked with only two tables in the past.
SELECT LAST_NAME
FROM EMPLOYEES
WHERE (DEPARTMENT_ID) IN
(SELECT DEPARTMENT_ID
FROM DEPARTMENTS
WHERE LOCATION_ID IN
(SELECT LOCATION_ID
FROM LOCATIONS
GROUP BY CITY
HAVING MIN(SALARY)));
This seems to be an assignment in an intro course in SQL. So let's assume you can't use analytic functions, match_recognize clause, etc. Just joins and aggregates.
In the subquery in the WHERE clause below, we compute the min salary for each city. We need to join all three tables for this. Then in the overall query we join the three tables again, and we use the subquery for an IN condition (a semi-join). The overall query looks like this:
select e.last_name
from employees e join departments d
on e.department_id = d.department_id
join locations l
on d.location_id = l.location_id
where ( e.salary, l.city ) in
(
select min(salary), city
from employees e join departments d
on e.department_id = d.department_id
join locations l
on d.location_id = l.location_id
group by city
)
;
You should separate out the concept of table joins from WHERE clauses.
Use WHERE for filtering data, use JOIN for connecting data together.
I think this is what you are wanting. By the way, lose the ALL CAPS if you can.
SELECT
LAST_NAME
FROM
EMPLOYEES
INNER JOIN (
SELECT
DEPARTMENTS.DEPARTMENT_ID,
CITY,
MIN(SALARY) AS LOWEST_SALARY
FROM
EMPLOYEES
INNER JOIN DEPARTMENTS ON EMPLOYEES.DEPARTMENT_ID = DEPARTMENTS.DEPARTMENT_ID
INNER JOIN LOCATIONS ON DEPARTMENTS.LOCATION_ID = LOCATIONS.LOCATION_ID
GROUP BY
DEPARTMENTS.DEPARTMENT_ID,
LOCATIONS.CITY
) AS MINIMUM_SALARIES
ON EMPLOYEES.DEPARTMENT_ID = MINIMUM_SALARIES.DEPARTMENT_ID
AND EMPLOYEES.SALARY = MINIMUM_SALARIES.LOWEST_SALARY
First of all join the tables, so you see city and employee in one row. If we group by city we get the minimum salary per city.
with city_employees as
(
select l.city, e.*
from locations l
join departments d using (location_id)
join employees e using (department_id)
)
select last_name
from city_employees
where (city, salary) in
(
select city, min(salary)
from city_employees
group by l.city
);
It is easier to achieve the same, however, with window functions (min over or rank over here).
select last_name
from
(
select
e.last_name,
e.salary,
min(e.salary) over (partition by l.city) as min_salary
from locations l
join departments d using (location_id)
join employees e using (department_id)
)
where salary = min_salary;

SQL inner join and subquery

I am trying to use a sub query on an inner join to get back all department numbers and names from a table that do not have programmer in the department, but I am having a little trouble as it returns no values. Here is my code, thanks for any help.
select Departments.Department_Name, Departments.Department_No
from employees inner join departments
on departments.department_No = employees.Department_No
where Employees.Department_No !=
(select Department_Name
from Employees, Departments
where Job_ID = '%pro%')
From what I can gather, you want something like this:
select d.Department_Name, d.Department_No
from departments d
WHERE NOT EXISTS (SELECT 1 FROM Employees
WHERE d.Department_No = Department_No
AND Job_ID LIKE '%pro%')
This selects all departments, for which there doesn't exist an employee whose job_ib contains 'pro'.
Try this one:
select d1.Department_Name,d1.Department_No
from departments d1
where d1.Department_No in ( select e1.Department_No
from Employees e1
where e1.Department_No=d1.Department_No and
e1.job_id not in ('programmer'));

How to add subquery as a column in SQL

How do I add a subquery as a column in my SQL script?
e.g.
Select emp_no, name,gender ,
(select department_name from departments where employees.emp_no = departments.emp_no)
from employees
PS: I'm using oracle 8
Going by the semantics, what I understand is that you want an employee's department name to be shown alongside his/her other information. I would suggest you do a join instead:
Select emp_no, name, gender, department_name
from employees emp, departments dept
where emp.emp_no = dept.emp_no;
That looks reasonably sound, I would suggest some (possible typos) cleaning up: add a comma after "gender" and declare the table names, also set the subquery alias
Select employees.emp_no, employees.name, employees.gender,
(select departments.department_name from departments where employees.emp_no = departments.emp_no) as dept_name
from employees
Alternatively, a nice join would would work too, if the other data is feasible:
Select employees.emp_no, employees.name, employees.gender, departments.department_name
from employees
inner join departments on employees.emp_no = departments.emp_no
left join is the best-practice, and should be faster in performance:
Select e.emp_no, e.name, e.gender , d.department_name
from employees e left join departments d on e.emp_no = d.emp_no;
You seem to be missing comma after gender.
Select emp_no, name,gender ,
(select department_name from departments where employees.emp_no = departments.emp_no) as dept_name from employees
The below is what you need. Just added a comma after gender. This subquery would need to return only one row for each result as well or else an error will be seen.
Select emp_no, name,gender,
(select department_name from departments where employees.emp_no = departments.emp_no)
from employees
This query is your answer but it will work only if there is one column mentioned in that if we use more than one column than it will retrun an error .
"Select employee_id,first_name,
(select department_name,manager_id from departments where employees.department_id = departments.department_id) as new_column
from employees;"
can you try this:
SELECT em.emp_no, em."name",em.gender ,
(SELECTdistinctdp.department_name
FROM departments dp
WHERE em.emp_no = dp.emp_no) my_sub
FROM employees em

SQL COUNT(*) returning the wrong answer

The following script should return the name of the departments and the number of employees that are in those departments, the Marketing,Executive and Sales departments have '0' employees but instead of '0' , the returned value is '1'. How can I correct it?
select Department, Departments.DepartmentID, count(*) as 'NumOfEmps'
from Departments
left join Employees
on Employees.DepartmentID = Departments.DepartmentID
group by Departments.DepartmentID,Department
You can't do that all in one query. You need a sub-query to get the employee counts first, then get the related department information (name, etc.) using the aggregated results:
SELECT Department, Departments.DepartmentID, t.NumOfEmps
FROM Departments
LEFT JOIN (SELECT DepartmentID, count(*) as 'NumOfEmps'
FROM Employees
GROUP BY DepartmentID) t
ON t.DepartmentID = Departments.DepartmentID
I'm making some assumptions about your schema since it's not listed. Column names may be off a bit, but this is the general idea. Hope it helps.
Don't use Count(*) count the thing you want to count namely the employees.
Count(*) counts the whole row. Since there's always going to be at least one record for each Department in Departments when you do count(*) you'll always get at least 1
SELECT d.Department, d.DepartmentID, count(e.EmployeeID)
FROM Departments d
LEFT JOIN employees e
ON d.DepartmentID = e.DepartmentID
GROUP BY
d.Department, d.DepartmentID
DEMO