same table, 1 field to 2 field query - sql

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

Related

SELECT or JOIN using same column twice

So I have three tables: Employee, Secretary and Manager
Given Schema
The Employee table has the following columns:
Employee_Number
Name
Home Address
Telephone Number
The Secretary table contains:
Secretary_Number
Employee_Number (linked with foreign key to Employee table)
Manager_Number (linked with foreign key to Manager table)
The Manager table contains:
Manager_Number
Employee_Number (linked with foreign key to Employee table)
What's required and what I tried
I am trying to do a JOIN so that I can see following columns:
Secretary's Number
Secretary's Name
Manager's Number
Manager's Name
I have the following join statement, which shows all the columns, and shows the Secretary's name and number, as well as the Manager Number:
SELECT
SECRETARY.SECRETARY_NUMBER,
SECRETARY.EMPLOYEE_NUMBER AS SECRETARY_EMPLOYEE,
EMPLOYEE.NAME AS SECRETARY_NAME,
SECRETARY.MANAGER_NUMBER,
MANAGER.EMPLOYEE_NUMBER AS MANAGER_EMPLOYEE,
EMPLOYEE.NAME AS MANAGER_NAME
FROM SECRETARY, MANAGER, EMPLOYEE
WHERE SECRETARY.MANAGER_NUMBER = MANAGER.MANAGER_NUMBER
AND SECRETARY.SECRETARY_NUMBER = EMPLOYEE.EMPLOYEE_NUMBER
AND MANAGER.EMPLOYEE_NUMBER = EMPLOYEE.EMPLOYEE_NUMBER;
Problem
But I can't get the Manager's Name to show up, or not repeat the same info as Secretary Name.
Any help would be greatly appreciated!
SELECT
s.SECRETARY_NUMBER,
s.EMPLOYEE_NUMBER AS SECRETARY_EMPLOYEE,
e.NAME AS SECRETARY_NAME,
s.MANAGER_NUMBER,
m.EMPLOYEE_NUMBER AS MANAGER_EMPLOYEE,
e2.NAME AS MANAGER_NAME
FROM
SECRETARY s
INNER JOIN
EMPLOYEE e
ON
e.EMPLOYEE_NUMBER = s.EMPLOYEE_NUMBER
INNER JOIN
MANAGER m
ON
m.EMPLOYEE_NUMBER = s.MANAGER_NUMBER
INNER JOIN
EMPLOYEE e2
ON
e2.EMPLOYEE_NUMBER = m.EMPLOYEE_NUMBER;

sum and join in sql

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;

SQL query - Dept and Employee table, some departments may not have managers

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.

How can I select two columns from two tables?

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.

does anyone know how to list the empid and the name of all supervisors if supervisors are in employee table too?

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