How to decode a column using another column? - sql

im new to sql and i have the following problem.
I have this kind of table with employee number, surname, job and a column named 'dir' that shows the employee number of the director of the employee in that row.
I was trying to do it using the decode function with some subqueries but failed :(.
Is there any way to do it with decode? I have not learned yet more advanced functions.
emp_no
Surname
Job
dir
1
a
director
2
b
analist
1
3
c
director
4
d
manager
1
5
e
analist
3
--------
--------
--------
--------
I need to write a query that will show in the first column, every employee's name and, in the second column, the name of that employee's director, or in case he has no director the legend "has no director".
Example:
Surname
director
a
has no director
b
a
c
has no director
d
a
e
c
Thanks in advance everyone!!

select a.Surname,
case when a.dir is null then 'has no director'
else b.Surname end as director
from employee a
left join employee b on a.dir=b.emp_no
order by Surname;
You can see the example here ;
http://sqlfiddle.com/#!9/d6217d9/18

Related

matching pair of employees in a same department

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 ;

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

Oracle SQL - finding sets that contain another set

Say I have a table A that contains a list of a potential employees ID's and their professional skills in the form of a skill code:
ID | skill code
005 12
005 3
007 42
007 8
013 6
013 22
013 18
And I have another table B that lists several job position ID's and their corresponding required skill ID's:
Job ID | skill code
1 3
1 32
1 21
1 44
2 15
2 62
.
.
.
How can I find out which Job Id's a specific person is qualified for? I need to select all Job Id's that contain all the person's skills. Say for instance I need to find all job ID's that employee ID 003 is qualified for, how would I structure an Oracle SQL query to get this information?
I want to be able to enter any employee ID in a WHERE clause to find what jobs that person is qualified for.
An idea would be to count the number of skills for every person and job:
SELECT A.id as person_id,
B.JOB_ID
FROM A
JOIN B
ON A.skill_code=B.skill_code
GROUP BY a.id, b.job_id
HAVING count(*) = (select count(*) from b b2 where b2.job_id = b.job_id);
Not tested and assuming that tables are well normalized.
UPDATE after the OP's comment.
It is asked for all the jobs which necessitate all skills of a person:
SELECT A.id as person_id,
B.JOB_ID
FROM A
JOIN B
ON A.skill_code=B.skill_code
GROUP BY a.id, b.job_id
HAVING count(*) = (select count(*) from a a2 where a2.job_id = b.job_id);
Update2: The question was updated with:
I want to be able to enter any employee ID in a WHERE clause to find what jobs that person is qualified for.
For this, you just add WHERE a.id = :emp_id to the first query. (above group by)
Try this one
WITH b1 AS
(SELECT job_id,
skill,
COUNT(*) over (partition BY job_id order by job_id) rr
FROM b
) ,
res1 AS
(SELECT a.id,
b1.job_id,
rr,
COUNT(*) over (partition BY id, job_id order by id) rr2
FROM A
JOIN B1
ON A.skill=B1.skill
)
SELECT id, job_id FROM res1 WHERE rr=rr2

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;