These are my tables
create table employees
(emp_no integer not null,
emp_name char(25),
age integer,
department_id integer not null,
salary integer,
CONSTRAINT employees_pk PRIMARY KEY(emp_no),
CONSTRAINT fk_Department FOREIGN KEY(department_id)
REFERENCES Department(department_id));
insert into employees values ( 15,'sara',30 ,101 ,2000 )
insert into employees values ( 12,'maha',29 ,104 ,3000 )
insert into employees values ( 14,'ahmad',24 , 102,4400 )
insert into employees values ( 11,'ali', 27, 103, 2500)
insert into employees values ( 13,'nora', 35, 101,3500 )
create table Works
(emp_no integer not null,
hurs integer,
department_id integer not null,
CONSTRAINT Works_pk PRIMARY KEY(emp_no),
CONSTRAINT Department_fk FOREIGN KEY(department_id)
REFERENCES Department(department_id));
insert into Works values ( 11,7,103)
insert into Works values (12,9,104)
insert into Works values (13,5,101)
insert into Works values (14,10,102)
insert into Works values (15,8,101)
create table Department
(Department_id integer not null,
dep_name char(50),
CONSTRAINT Department_pk PRIMARY KEY(Department_id));
insert into Department values (101,'computer')
insert into Department values (102,'history')
insert into Department values (103,'english')
insert into Department values (104,'physics')
And I want to select the employee names and their department names and these are my commands non worked properly:
select emp_name
from employees
select dep_name
from Department
select emp_name
from employees
union
select dep_name
from Department
select emp_name, dep_name
from Department
cross join employees
SELECT employees.emp_name, Department.dep_name
FROM employees, Department
where employees.emp_name = Department.dep_name
select emp_name, Department.dep_name
from employees
inner JOIN Department on employees.emp_name = Department.dep_name
select
count(distinct employees.emp_name)
from
employees
where
employees.emp_name not in (select distinct Department.dep_name
from Department)
select (employees.emp_name)
from employees
where employees.emp_name not in (select Department.dep_name
from Department)
Also I want to select employee name and sum of their salary who are working hour is greater than or equal 20 and my command didn't work:
select
emp_name, sum(salary)
from
employees
union
select
hurs
from
works
where
hurs >= 20
Where did I go wrong here?
First, to get the workers' name and their department, you should be linking table employees and department using department_id, not name..
select emp_name,Department.dep_name
from employees inner JOIN Department
on employees.department_id = Department.Department_id
and for the employees whose working hours are >=20:
select employees.emp_name
from employees join works
on employees.emp_no=works.emp_no AND works.hurs>=20
and their total salary:
select sum(employees.salary)
from employees join works
on employees.emp_no=works.emp_no AND works.hurs>=20
note: inner join and join are the same thing..
In short, you should realize that linking the tables using join is relatively intuitive..
you are linking them based on the "same" column that the both tables own..
[one of them is a foreign key of the other (primary) key]
UPDATE:
you can display the employees' names and their total salary together as the following, but it would seem redundant..
select employees.emp_name, sum(employees.salary)
from employees join works
on employees.emp_no=works.emp_no AND works.hurs>=20
group by employees.emp_name
To union two SELECT results they have to have
same selected column count
same type of
What you actually want to use is INNER JOIN :
SELECT emp_name,sum(salary) FROM employees
INNER JOIN works ON employees.emp_no = works.emp_no
WHERE works.hurs >= 20
The correct syntax is as follows:
SELECT employees.emp_name,
Department.dep_name
FROM employees, Department
WHERE employees.department_id = Department.department_id
or with shorthand:
SELECT e.emp_name,
d.dep_name
FROM employees as e, Department as d
WHERE e.department_id = d.department_id
A description of what is going on:
The SELECT section should contain a list of columns that you want separated by commas. You can explicitly reference a column from table as shown in the examples.
The FROM section should contain a list of tables you wish to join separated by commas. You can provide shorthand names for the tables, as shown in the second example.
The WHERE section allows you to mark which columns are related between the two tables.
Related
I need to create a view that reports the department name and how many employees don't work on any projects controlled by that department.
I know how to create a view, an also have figured out ways to get the count of how many employees do work on projects for a department via joins, but cannot figure out how to get the number of employees that don't, paired with that department. This is general SQL and not tied to particular DBMS, so I probably need to avoid obscure SQL commands limited to a specific DBMS.
I have created a mock up of the parts of the schema I believe relevant to the problem here:
Create Table DEPARTMENT (Dname VARCHAR(30), Dnumber INTEGER primary key , Mgr_ssn INTEGER, Mgr_start_date Varchar(30));
INSERT INTO Department (Dname,Mgr_ssn,Mgr_start_date) values ('maths',1,'foo');
INSERT INTO Department (Dname,Mgr_ssn,Mgr_start_date) values ('physics',2,'foo');
Create Table PROJECT (Pname VARCHAR(30), Pnumber INTEGER primary key , Plocation varchar(10), Dnum INTEGER);
INSERT INTO PROJECT (Pname,Plocation,Dnum) values ('project','the moon',1);
INSERT INTO PROJECT (Pname,Plocation,Dnum) values ('project','the moon',1);
INSERT INTO PROJECT (Pname,Plocation,Dnum) values ('project','the moon',2);
INSERT INTO PROJECT (Pname,Plocation,Dnum) values ('project','the moon',2);
INSERT INTO PROJECT (Pname,Plocation,Dnum) values ('project','the moon',2);
Create Table EMPLOYEE (Fname VARCHAR(30), SSn INTEGER primary key);
INSERT INTO EMPLOYEE (Fname) VALUES ('rick');
INSERT INTO EMPLOYEE (Fname) VALUES ('rick');
INSERT INTO EMPLOYEE (Fname) VALUES ('rick');
INSERT INTO EMPLOYEE (Fname) VALUES ('rick');
INSERT INTO EMPLOYEE (Fname) VALUES ('rick');
Create Table WORKS_ON (Essn INTEGER,Pno INTEGER, primary key(Essn,Pno));
INSERT INTO WORKS_ON VALUES(1,1);
INSERT INTO WORKS_ON VALUES(2,4);
INSERT INTO WORKS_ON VALUES(3,3);
INSERT INTO WORKS_ON VALUES(4,4);
INSERT INTO WORKS_ON VALUES(4,3);
INSERT INTO WORKS_ON VALUES(4,2);
While this is an academic exercise, this is not an assignment, and so if I don't get this done, or otherwise get help with a solution, i'll never know how to tackle these types of queries.
The very first thing I had tried was getting a count of every employee that exists, then trying to subtract the count of every employee who works on projects for each department, but I couldn't get the arithmetic to work on all the rows. I have been unable to get other solutions using SET Minus and sub queries working.
Edit: what I had to get counts of employees working on projects for each department:
SELECT Dnumber, count(*) num_employees_on_projects FROM department d
INNER JOIN PROJECT p on d.Dnumber = p.Dnum
INNER JOIN WORKS_ON w on w.Pno = p.Pnumber
INNER JOIN EMPLOYEE e on e.Ssn = w.essn
group by Dnumber
You need to switch to outer joins to include non-matching rows. And then you count a column from the right most table (WORKS_ON) which is known to be NOT NULL, easiest one is the join column:
SELECT Dnumber,
count(*) as all_employees,
count(w.Pno) as employees_on_projects,
count(*) - count(w.Pno) as employees_without_project
FROM department d
LEFT JOIN PROJECT p on d.Dnumber = p.Dnum
LEFT JOIN WORKS_ON w on w.Pno = p.Pnumber
-- LEFT JOIN EMPLOYEE e on e.Ssn = w.essn -- not needed
group by Dnumber;
Edit:
To relate the data per department to the overall count of employees you might add a Scalar Subquery:
SELECT Dnumber,
count(w.Pno) as employees_on_projects,
(SELECT count(*) FROM EMPLOYEE) -- all employees
- count(w.Pno) as employees_without_project
FROM department d
LEFT JOIN PROJECT p on d.Dnumber = p.Dnum
LEFT JOIN WORKS_ON w on w.Pno = p.Pnumber
group by Dnumber;
See fiddle
I don't understand why my solution is not working.
I am trying to count the number of employees by department in a database.
There are two tables:
CREATE TABLE DEPARTMENT
(
NAME VARCHAR(32) NOT NULL,
ID INT NOT NULL PRIMARY KEY
);
CREATE TABLE EMPLOYEE
(
NAME VARCHAR(32) PRIMARY KEY NOT NULL,
DEPARTMENT INT NOT NULL REFERENCES DEPARTMENT(ID)
);
and I have created a view to show the number of employees in departments.
CREATE
OR REPLACE VIEW VIEW_NB AS
SELECT
DEPARTMENT.NAME AS DEPARTEMENT,
count(*) AS nb
FROM
DEPARTMENT
LEFT JOIN
EMPLOYEE
ON DEPARTMENT.ID = EMPLOYEE.DEPARTMENT
GROUP BY
DEPARTMENT.ID,
DEPARTMENT.NAME;
SELECT
ADD_DEPARTMENT('FRANCE', 10);
SELECT
ADD_DEPARTMENT('SPAIN', 100);
SELECT
ADD_EMPLOYEE('JOSE', 10);
result is
departement | nb
-------------+----
FRANCE | 1
SPAIN | 1
but it should be
departement | nb
-------------+----
FRANCE | 0
SPAIN | 1
I understand the need to use left joins.
However my view has at least 1 employee for every department, even when they don't have employee.
Did I miss something? If yes what?
This should work:
SELECT DEPARTMENT.NAME AS DEPARTEMENT, count(EMPLOYEE.DEPARTMENT) AS nb
FROM DEPARTMENT
LEFT JOIN EMPLOYEE
ON DEPARTMENT.ID = EMPLOYEE.DEPARTMENT
GROUP BY DEPARTMENT.ID, DEPARTMENT.NAME;
The reason you're getting 1 as a count is because you used * , which means - count any record as 1 no matter the data. COUNT() ignore NULL by default, so all you have to do is provide one of the right(detail) table columns inside it .
Change first line
SELECT DEPARTMENT.NAME AS DEPARTEMENT, count(*) AS nb
FROM DEPARTMENT
LEFT JOIN EMPLOYEE
ON DEPARTMENT.ID = EMPLOYEE.DEPARTMENT
GROUP BY DEPARTMENT.ID, DEPARTMENT.NAME;
TO
SELECT DEPARTMENT.NAME AS DEPARTEMENT, count(EMPLOYEE.DEPARTMENT) AS nb
^^^^^^^^^^^^^^^^^^
You need to count the rows from the "outer" table. Because aggregates ignore NULL values, those rows that did no have a match in the employee table will be ignored by the count() function:
SELECT department.name AS departement,
count(employee.department) AS nb
FROM department
LEFT JOIN employee ON department.id = employee.department
GROUP BY department.id,
department.name;
There are two tables:
Employee
---------
emp_id
emp_name
emp_contact
salary
mgr_emp_Id
Dept_No
Dept
-----
Dept_No
Dept_name
Dept_Location
Write a SQL statement to list all department names along with location and also manager name if a manager has been assigned to the department. Note that some departments still do not have a manager.
Is the following correct?
SELECT Dept_name, Dept_Location, emp_name AS Mgr_name
FROM Dept
LEFT JOIN Employee ON (Dept.Dept_No = Employee.Dept_No AND mgr_emp_id = emp_id)
Can this be achieved without join too? If yes, how?
Yes, you can achieve that without a JOIN, even though I prefer using JOINs. Your query will have to be modified. Here's how...
Example
http://sqlfiddle.com/#!2/596b45/4 (MySQL 5.5)
http://sqlfiddle.com/#!3/bbad4/1 (SQL Server 2008)
http://sqlfiddle.com/#!12/bbad4/1 (PostgreSQL 9.2)
Assumption
1) In the employee table: manager id + department id will be unique
2) In the employee table: if employee Clark is ID 5 and has a manager with ID 1, there will a record in the table with ID 1
3) MySQL 5.5 is being used
Structure
create table dept
(
dept_no int not null,
dept_name varchar(100) not null,
dept_location varchar(100) not null,
primary key (dept_no)
);
create table employee
(
emp_id int not null,
emp_name varchar(100) not null,
mgr_emp_id int,
dept_no int not null,
primary key (emp_id),
key employee_mgr_emp_id (mgr_emp_id),
foreign key fk_employee_dept_dept_no (dept_no) references dept (dept_no) on delete no action on update no action
);
insert into dept values
(1, 'Dept-1', 'Chicago'),
(2, 'Dept-2', 'London');
insert into employee values
(1, 'Clark Mgr', null, 1),
(2, 'Cameron Emp', 1, 1),
(3, 'Charlie Emp', 1, 1),
(4, 'Layton Emp', null, 2),
(5, 'Linda Emp', null, 2);
MySQL 5.5 query
Without JOIN
select
list.*,
emp_id,
emp_name
from employee,
(
select
distinct
dept.dept_no,
dept.dept_name,
dept.dept_location,
employee.mgr_emp_id
from dept, employee
where
dept.dept_no = employee.dept_no
and employee.mgr_emp_id is not null
) list
where
employee.emp_id = list.mgr_emp_id;
With JOIN (although not completely identical to the above. I prefer using JOINs)
select
list.*,
emp_id,
emp_name
from employee
inner join
(
select
distinct
dept.dept_no,
dept.dept_name,
dept.dept_location,
employee.mgr_emp_id
from dept
left join employee on dept.dept_no = employee.dept_no
where
employee.mgr_emp_id is not null
) list
on employee.emp_id = list.mgr_emp_id;
How does it work
First we want to get a list of all departments that have a manager ID of not null in the employee table. To do that, we use this query below. This query will give 2 records for Chicago because there are 2 records in employee table with a valid manager ID for Chicago's department.
Without JOIN
select
dept.dept_no,
dept.dept_name,
dept.dept_location,
employee.mgr_emp_id
from dept, employee
where
dept.dept_no = employee.dept_no
and employee.mgr_emp_id is not null;
With JOIN
select
dept.dept_no,
dept.dept_name,
dept.dept_location,
employee.mgr_emp_id
from dept
left join employee on dept.dept_no = employee.dept_no
where
employee.mgr_emp_id is not null;
To get only one record, we will use distinct keyword:
select
distinct
dept.dept_no,
...
Great, so now we know who the manager is for each department no. Let's find this person's name. To do that, we put our query in a subquery (which I nicknamed/aliased as list) and then combine it with employee table to get the desired result.
I have a table that contains empid, name, salary, hiredate, position and supervisor (which includes empid, not the name). How do I list the empid and name of all supervisors?
The output has to have to columns supervisor (and a list of their empid) and their names. This is the create statement used to create the Employee table:
/* Create table Employee */
IF OBJECT_ID('Employee', 'U') IS NOT NULL
DROP TABLE Employee
GO
CREATE TABLE Employee (
emp_id NCHAR(5),
name NVARCHAR(20),
position NVARCHAR(20),
hire_date DATETIME,
salary MONEY,
bcode NCHAR(3),
supervisor NCHAR(5)
)
I have tried a variety of statements using having statement and count but they don't seem to work.
select emp_id, name from employee where position='manager';
I tried this but it doesn't work. Anyone smart that knows how to do it?
You will have to join the table back on itself:
select a.name, a.position, a.hiredate, a.salary, a.supervisorid,
isnull(b.name, '') as SupervisorName
from EmployeeTable a
left join EmployeeTable b
on a.SupservisorID=b.ID
The left join will make sure that the employees who do not have supervisors are returned, and isnull(b.name, '<NONE>') can be used if you would like to have something other than NULL as a value in those cases.
SELECT e.empid ,ISNULL(b.name, 'No supervisor') SupervisorName
FROM employee e LEFT JOIN employee b
ON e.supervisorid = b.empid
Inner join will leave out the people who do not have a supervisor , Use left join to get all the employees
If you want supervisors only, you just need to select rows whose emp_id values are found in the supervisor column:
SELECT
SupervisorID = emp_id,
SupervisorName = name
FROM dbo.Employee
WHERE emp_id IN (SELECT supervisor FROM dbo.Employee)
;
I have 2 tables: 1st holds employees (of ones in any position) and the 2nd holds manager employee relations with id numbers.
I want to write a query like
1st field: name(employee),
2nd field: name(manager)
How can I do that?
No nested queries required, just use standard joins:
select e.*, m.*
from
employee e
left join employee_managers em
on e.id = em.emp_id
left join employee m
on m.id = em.man_id
Each row will contain all fields of employee (possibly several rows for one employee if it has several associated managers) and all fields of his corresponding manager (or NULLs if employee has no manager).
You can do that with one table:
Employee
--------
EmployeeId int
Name varchar(50)
ManagerId int
ManagerId points to the manager's entry in the same table. The CEO will have a ManagerId of null. An example table definition:
create table Employees (
EmployeeId int auto_increment primary key
, Name varchar(50)
, ManagerId int
, foreign key (ManagerId) references Employees(EmployeeId)
);
With some example data:
insert into Employees (Name) select 'The Chief';
insert into Employees (Name, ManagerId) select 'Grunt 1',
(select EmployeeId from Employees where Name = 'The Chief');
insert into Employees (Name, ManagerId) select 'Grunt 2',
(select EmployeeId from Employees where Name = 'The Chief');
insert into Employees (Name, ManagerId) select 'Secretary',
(select EmployeeId from Employees where Name = 'The Chief');
To find the name of the second Grunt's manager, you could query like:
select mgr.Name
from Employees mgr
inner join Employees grunt
on grunt.managerid = mgr.employeeid
where grunt.name = 'Grunt 2';