matching pair of employees in a same department - sql

I'm trying to make a list of employees working in a same department like:
employeeName
department
employeeName
Tim
2
kim
Tim
2
Jim
Kim
2
Tim
Kim
2
Jim
Jim
2
Kim
Jim
2
Tim
Aim
3
Sim
Sim
3
Aim
But the only thing i can do for now is:
SELECT emp_name, dept_code
FROM employee
WHERE dept_code IN (SELECT dept_code FROM employee);
employeeName
department
Tim
2
Kim
2
Jim
2
Aim
3
Sim
3
How can I make a list pairing with the employee working in a same department? thanks gurus...

To first point that out: I dislike your idea to create such a result listing "pairs" twice and would prefer another, easier query whose results would be better to read. I will come back to this later in this answer.
But anyway, if you really want to produce the outcome you have shown, we can do this with CROSS JOIN. This builds all combinations of employees.
In the WHERE clause, we will set the conditions that they must work in the same department, but have different names:
SELECT
e1.emp_name AS employeeName,
e1.dept_code AS department,
e2.emp_name AS employeeName
FROM
employee e1
CROSS JOIN employee e2
WHERE
e1.dept_code = e2.dept_code
AND e1.emp_name <> e2.emp_name
ORDER BY e1.dept_code, e1.emp_name, e2.emp_name;
To come back to the idea to make this much easier and better to read: We can just use LISTAGG with GROUP BY to produce a comma-separated list of employees per department. I highly recommend to use this approach due to much better performance and readability.
This query will do on new Oracle DB's:
SELECT dept_code,
LISTAGG (emp_name,',') AS employees
FROM employee
GROUP BY dept_code;
On older Oracle DB's, we need to add a WITHIN GROUP clause:
SELECT dept_code,
LISTAGG (emp_name,',')
WITHIN GROUP (ORDER BY emp_name) AS employees
FROM employee
GROUP BY dept_code;
This will produce following result for your sample data:
DEPT_CODE
EMPLOYEES
2
Jim,Kim,Tim
3
Aim,Sim
Here we can try out these things: db<>fiddle

You will get all the pairs (A,B) and (B,A) of employees in the same department at the exclusion of all (A,A) with:
SELECT e1.emp_name AS first_emp_name, e1.dept_code, e2.emp_name AS second_emp_name
FROM employee e1
JOIN employee e2 ON e1.dept_code = e2.dept_code AND e1.emp_name <> e2.emp_name ;

Related

Get count of total employees under each manager (SQL Server)

I need to get, for each of the five people in this table, the total employees reporting to each one of them (either directly or indirectly).
CREATE TABLE employees
([employee] nvarchar(30), [manager] nvarchar(30))
;
INSERT INTO employees
([employee], [manager])
VALUES
('Robert', null),
('Julian', 'Robert'),
('Sophie', 'Robert'),
('Lucy', 'Julian'),
('John', 'Lucy')
;
The output I expect is:
employee
subordinates
Robert
4
Julian
2
Lucy
1
Sophie
0
John
0
I have searched everywhere how to do this type of recursion/hierarchical query, and it seems it is very common to approach this kind of exercise to get the employee hierarchy only (which I managed to do already), but not the total count of employees under each manager.
The best I could get was the following, but it only gets the count for the top manager, while I need it for all employees in the company in a single table (from an answer to this post: SQL Query to get recursive count of employees under each manager).
WITH EmployeeCTE
AS (SELECT e.employee, e.manager as topmanager
FROM employees e, employees m
WHERE e.manager = m.employee AND m.manager IS NULL
UNION ALL
SELECT e.employee, mgr.topmanager
FROM employees e, EmployeeCTE mgr
WHERE e.manager = mgr.employee)
SELECT topmanager, count(*)
FROM EmployeeCTE AS u
GROUP BY topmanager;
Here is a Fiddle to this: http://sqlfiddle.com/#!18/380ba/2
The problem is with getting the zero subordinates for those without subordinates.
One way to get them is via a LEFT JOIN of all employees to the results of the recursive CTE.
WITH CTE_Employees AS (
SELECT employee
FROM employees
GROUP BY employee
)
, RCTE_Managers AS (
SELECT
manager as base_manager
, 1 as depth
, employee
, manager as direct_manager
FROM employees
WHERE manager IS NOT NULL
UNION ALL
SELECT
cte.base_manager
, cte.depth + 1
, emp.employee
, emp.manager
FROM RCTE_Managers cte
JOIN employees emp
ON emp.manager = cte.employee
)
SELECT
emp.employee
, COUNT(DISTINCT mgr.employee) AS subordinates
FROM CTE_Employees emp
LEFT JOIN RCTE_Managers mgr
ON mgr.base_manager = emp.employee
GROUP BY emp.employee
ORDER BY COUNT(mgr.employee) DESC, emp.employee;
employee
subordinates
Robert
4
Julian
2
Lucy
1
John
0
Sophie
0
Test on db<>fiddle here

How to mark employees which are also manager

I need to determine whether an employee is any other employee's manager.
Given this table:
Employee Employee's Manager
---------- ------------------
Bob CN=Lisa
Amanda CN=Lisa
James CN=Art
Frank CN=Amanda
Amy CN=Art
I need this:
Employee Employee's Manager Employee IS Manager
---------- ------------------ -------------------
Bob CN=Lisa N
Amanda <-- CN=Lisa Y <--
James CN=Art N
Frank CN=Amanda <-- N
Amy CN=Art N
Because Amanda appears in the "Employee's Manager" column in another employee's row, I need to derive this, adding the additional "Employee IS Manager" field.
I've gotten as far as this (wrong!) subquery for the additional "IS Manager" field, but I do not know how to add it as a column in a subquery:
select
a.* ,
(select 'Y' as IsManager
where exists (select * from Employees b where b.Manager like '%' + #x+ '%' )
)
from Employees a
But I do not know how to make #x refer to Amanda in the Employee column in the other row.
EDIT: I should note that I am not necessarily looking for a "subquery" solution. A JOIN solution, or any other kind of solution is fine for my purposes. Thanks.
You are close but you need a case expression:
select e.* ,
(case when exists (select 1
from Employees m
where m.Manager like '%=' + e.employee_manager
)
then 'Y' else 'N' end
) as isManager
from Employees e;
Note that I tweaked the logic for matching so "Anne" and Roseanne" do not get confused. If the manager always starts with 'CN=', then use like 'CN=' + instead.
You can also use outer apply to get your desired result. Here through outer apply we are getting 'Y' when an employee is also a manager other wise it's returning null. Coalesce() is used to convert null to 'N'.
Schema and insert statements:
create table Employees (Employee varchar(50),employee_Manager varchar(50));
insert into Employees values('Bob', 'CN=Lisa');
insert into Employees values('Amanda', 'CN=Lisa');
insert into Employees values('James', 'CN=Art' );
insert into Employees values('Frank', 'CN=Amanda');
insert into Employees values('Amy', 'CN=Art' );
Query:
select
a.*,coalesce(isManager,'N')[Employee IS Manager]
from Employees a outer apply(select 'Y' from Employees b where b.employee_manager='CN='+a.Employee)manager (isManager)
Output:
Employee
employee_Manager
Employee IS Manager
Bob
CN=Lisa
N
Amanda
CN=Lisa
Y
James
CN=Art
N
Frank
CN=Amanda
N
Amy
CN=Art
N
db<fiddle here

SQL Subquery or Group BY to return Distinct values of a certain column?

I am running into an issue where I know I am close to a solution but I cannot get the right data to come back or am getting errors on the queries.
Basically what I want to do is to select values from a single table based on the following: I want them based on an employee name I supply and I want them to return DISTINCT Account Numbers for that employee(sometimes the same account number is listed more than one time...I only want one row of data from each duplicate account number).
Here is what I have tried so far:
SELECT DISTINCT * FROM Employees WHERE EmpName = 'Mary Johnson' GROUP BY AccountID
-This returns an error saying I don't have an aggregate for the column EmployeeID(which isn't a calculated column, so why is it asking for an aggregate??)
Then I tried a subquery:
SELECT EmployeeID, EmpName, Department, Position, (SELECT DISTINCT AccountID From Employees) AS AcctID FROM Employees WHERE EmpName = 'Mary Johnson'
-This gives me an error saying AT Most one record can be returned(I'm in Access).
I know there has to be a solution to what I am looking for---Currently If I do a full query just on EmpName it returns 30 records, however, 23 of them have a duplicate AccountID, so there should only be 7 records that return with a DISTINCT AccountID.
How can I achieve this via SQL?
Here is an Example:
ID(PK) EmpName AcctID Department Position EmpId
------ -------- --------- -------- -------- ------
1 Mary Johnson 1234 IT Tech 226663
2 Mary Johnson 1234 IT Tech 226663
3 Mary Johnson 1234 IT Tech 226663
4 Mary Johnson 2345 IT Tech 226663
5 John James 23442 Banking Teller 445645
6 Jame Tabor 1234 HR Manager 234555
In the example above I want to do an SQL Query to get the rows back with the AccountId's for Mary Johnson that are DISTINCT. So We would get back 2 rows Mary Johnson 1234 and Mary Johnson 2345, ignoring the other 2 rows that Mary Johnson has with duplicate AccountIDs of 1234 and the other rows with employees not named Mary Johnson
This is not really easy to do in MS Access -- it lacks row_number(). One method is to use another column that uniquely identifies each row that has the same AccountID:
select e.*
from Employees as e
where e.?? = (select max(e2.??)
from Employees as e2
where e2.AccountId = e.AccountId and e2.empName = e.empName
);
The ?? is for the column that uniquely identifies the rows.
If you only care about two columns, then use select distinct:
select distinct e.empName, e.AccountId
from employees as e;
You an add a where clause to either query to restrict to a single employee. However, it doesn't make sense to me that a table called Employees would have multiple rows for a single employee name (except in the rare case of people with the same names).
The reason you are getting the error about "you can only return one row" is because you are using a subquery to feed into a record row. In that case, you are searching for distinct AcctIDs for Mary Johnson, she has two distinct ones, so the query fails. If you used MIN(AcctID) that query would work fine. Therefore, this will work:
SELECT EmployeeID, EmpName, Department, Position, MIN(AccountID )
FROM Employees
WHERE EmpName = 'Mary Johnson'
GROUP BY EmployeeID, EmpName, Department, Position
The next question you need to ask yourself is WHICH AccountID do you want to see? You can switch to MAX, but if you have three values and you want the middle one, that will be a lot harder to solve. But, the above query will at least give you a working result.
EDIT:
That should give you only one row assuming you have identical information for Mary Johnson. If you are getting 24 it means you have different entries For empname, department, position, or employeeid. If you want to see all AccountIDs associated with Mary Johnson, use this:
SELECT EmployeeID, MIN(EmpName), AccountID, MIN(Department) AS Department, MIN(Position) AS Position
FROM Employees
WHERE EmpName = 'Mary Johnson'
GROUP BY EmployeeID, AccountID

will this sql work

Write ONE SQL statement that prints the name of all employees and their department numbers for all salaried employees who satisfy all of the following conditions:
Work on 2 projects,
Do not make $30000,
Their department manager and supervisor have the same name (Note: since name is not the pkey of employee tables, this requirement does not mean these two individuals are the same person).
Note that supervisor is not the manager of the department
SQL code:
select
ename, d#
from
employee, department
where
count(p#) = 2
and salary < 30000
and cname, d# in (select ename, d#
from employee, department
where employee.cname = depatment.cname);
This would be a good start for you, since there is some data missing about managers and supervisors (and generally you haven't provided any schema):
select ename
from employee e
join department d on e.cname = d.cname
where salary < 30000
group by ename
having count(p#) = 2
It will show up every employee with salary below 30K that works on 2 projects.
You're likely to need more joins/subqueries to achieve your desired output.

sql query .. confused

I am a newbie and i am not sure how to go about this .. can anybody help me ?
Given the following tables ...
DEPARTMENT
DEPT_ID NAME
1 HR
2 Technical
3 Marketing
4 Sales
EMPLOYEE
ID NAME DEPT_ID SALARY MANAGER_ID
1 Alex 2 2000
2 Sally 1 2000
3 Amit 2 1500 1
4 Jason 1 1500 1
... ... ... ... ...
Using the DEPARTMENT and EMPLOYEE tables from earlier, write a SQL query to print the number of employees working in each department. The output should look something like this:
NAME COUNT
HR 2
Technical 2
Marketing 0
Sales 0
Please note that not all departments have been staffed yet, so some departments may not have any employees. We still want these departments to appear in the results, with a zero count.
Using the EMPLOYEE table from earlier, write a SQL query to print out the number of employees working under each manager. The output should look something like this:
NAME COUNT
Alex 2
Sally 0
You need to join the tables, group by department, and take the count of rows per department.
Try This Link
Solution to the first part of the problem:
select d.NAME, count(e.NAME)
from EMPLOYEE as e
right join DEPARTMENT as d
on e.DEPT_ID = d.DEPT_ID
group by d.DEPT_ID
Solution to the second part of the problem (I'm not sure whether this one is correct or not):
select NAME, count(NAME)
from EMPLOYEE
group by MANAGER_ID
Please check the sqlfiddle: http://sqlfiddle.com/#!2/5e802/13
Try this it may help you :
a)
select d.Name as DepartmentName, count(e.id) as EmployeeCount from employee as e, department as d where e.DEPT_ID = d.DEPT_ID group by d.Name;
b)
select a.name as Manager_Name,Count(a.name) as EmployeeCount from employee a, employee b where a.id=b.MANAGER_ID group by a.name;