get items from one-level tree postgresql [duplicate] - sql

I have a table with the structure:
Employee_ID Employee_Name Manager_ID
And, for each employee, I need to show the top manager ID. I mean, if for example, I have the EmployeeID 2 whose manager is 3 and, therefore, the number 3 has the manager number 5, I would have to show:
Empoyee_ID--Top_Manager
2 5
I need to do this with a Recursive CTE in Postgres.

Something like (for the level 2 manager) :
WITH RECURSIVE T AS
(
SELECT EMPLOYEE_ID, EMPLOYEE_NAME, MANAGER_ID, 1 AS MANAGER_LEVEL
FROM MyTable
UNION ALL
SELECT T.EMPLOYEE_ID, T.EMPLOYEE_NAME, E.MANAGER_ID, MANAGER_LEVEL + 1
FROM MyTable AS E
JOIN T ON T.MANAGER_ID = E.EMPLOYEE_ID
WHERE T.MANAGER_LEVEL = 1 --> limiting to level 2 - 1
)
SELECT EMPLOYEE_ID, EMPLOYEE_NAME, MANAGER_ID
FROM T
WHERE MANAGER_LEVEL = 2 --> retrieving only level 2, not level 1 and 2

That's a typical recursive query. Here is one way to do it in Postgres:
with recursive cte as (
select 1 lvl, employee_id, manager_id from mytable
union all
select c.lvl + 1, c.employee_id, t.manager_id
from cte c
inner join mytable t on t.employee_id = c.manager_id
)
select distinct on (employee_id) employee_id, manager_id top_manager
from cte c
order by employee_id, lvl desc
The cte climbs up the hierarchy while keeping track of the original employee id and of the relationship level. The outer query filters on the top manager per employee.

Related

how to retrieve the employee who got maximum bonus?

I have to display the employee detail who has got the maximum bonus(one with employee details and another table with bonus details). Here I have created a 'performance bonus' column to sum up the multiple bonuses. How to retrieve the employee from that column?
select e.Employee_id,
e.First_name,
e.Department,
e.Salary,
coalesce((select sum(b.Bonus_Amount)
as Bonus-- Let's sum up all Employee's the bonuses
from Employee_Bonus_Table b
where b.Employee_ref_id = e.Employee_Id), 0) [Performance_bonus]
from Employee_Table e
If I understood the task correctly, then the bonuses can be repeated, is that right?
then we must first sum up all the bonuses by employee, then sort from largest to smallest and get the first one from the list
--- for examples:
with Employee_Bonus_Table as(
select Bonus_Amount = 1 ,Employee_ref_id = 1
union select Bonus_Amount = 1000 ,Employee_ref_id = 2
union select Bonus_Amount = 2000 ,Employee_ref_id = 2
),Employee_Table as (
select Employee_id=1
,First_name='First_name'
,Department= 'Department'
,Salary = 1000
UNION select Employee_id=2
,First_name='First_name2'
,Department= 'Department2'
,Salary = 2000
)
--reslut query:
select top 1
e.Employee_id,
e.First_name,
e.Department,
e.Salary,
b.sumBonus_Amount
from Employee_Table e
join (select sumBonus_Amount = sum(Bonus_Amount), Employee_ref_id
from Employee_Bonus_Table
group by Employee_ref_id
) b on b.Employee_ref_id = e.Employee_Id
order by b.sumBonus_Amount desc

Count id_employee in another column

Could someone help me how to count the number of times an employee
"id" is next to the another employee in the "executive" column?
In the first picture I am sending the table and the results I want. In the second picture the result I have
SELECT id_employee, lastname, COUNT(id_employee)
FROM employees
WHERE id_employee IN (SELECT executive FROM employees)
GROUP BY lastname, id_employee;
1
2
You need a self-join:
select iemp.d_employee, emp.last_name, subordinates
from employee as emp
join
( -- count per executive
select executive, count(*) as subordinates
from employee
group by executive
) as emp_count
on emp.id_employee = emp_count.executive
When you switch to an Outer Join you can include employees which are not executives:
select id_employee, last_name,
coalesce(subordinates, 0) -- to get zero instead of NULL
from employee as emp
left join
( -- count per executive
select executive, count(*) as subordinates
from employee
group by executive
) as emp_count
on emp.id_employee = emp_count.executive
You can try below query, simple and sweet.
SELECT * INTO #EMPLOYEE FROM
(SELECT 1001 as ID_EMP,'JAMES' as LASTNAME,NULL as EXECUTIVE
UNION
SELECT 1002 as ID_EMP,'JENSEN' as LASTNAME,1001 as EXECUTIVE
UNION
SELECT 1003 as ID_EMP,'RUDY' as LASTNAME,1001 as EXECUTIVE
UNION
SELECT 1004 as ID_EMP,'CZARNY' as LASTNAME,1002 as EXECUTIVE
UNION
SELECT 1005 as ID_EMP,'RAMBUS' as LASTNAME,1002 as EXECUTIVE
UNION
SELECT 1006 as ID_EMP,'ADAM' as LASTNAME,1003 as EXECUTIVE
)A
SELECT ID_EMP,A.COUNT FROM (SELECT EXECUTIVE,COUNT(*) AS COUNT FROM #EMPLOYEE GROUP BY EXECUTIVE)A LEFT JOIN #EMPLOYEE E
ON E.ID_EMP = A.EXECUTIVE

using join and group by...having giving error

SELECT d.DEPARTMENT_NAME
FROM Department d,
Student s
WHERE d.DEPARTMENT_ID = s.DEPARTMENT_ID
GROUP BY d.DEPARTMENT_NAME
HAVING COUNT(s.STUDENT_ID) < MAX(COUNT(s.STUDENT_ID));
The code is for joining student and department table. The department_id is key from department to student. Need to find departments with not the max number of students. Error is group function nested too deeply. Isn't nesting allowed up to 3?
Here is the exact error
ORA-00935: group function is nested too deeply
upd. Oh, shi~! I just mentioned the question's related to Oracle. I don't know its syntax for rank() function, but I think it should be really close to Sql Server.
Here it is:
;with Department(DEPARTMENT_ID, DEPARTMENT_NAME) as (
select 1, 'first' union all
select 2, 'second' union all
select 3, 'third'
)
, Student(STUDENT_ID, DEPARTMENT_ID) as (
select 1, 1 union all
select 2, 2 union all
select 3, 2 union all
select 4, 2 union all
select 5, 3 union all
select 6, 3 union all
select 7, 3
)
, DepOrdered as (
select
d.DEPARTMENT_ID,
d.DEPARTMENT_NAME,
s.StudentCnt,
-- rank departments by the number of students
rank() over (order by s.StudentCnt desc) as Rnk
from Department d
cross apply (
-- for every department count its students
select
count(s.STUDENT_ID) StudentCnt
from Student s
where
d.DEPARTMENT_ID = s.DEPARTMENT_ID
) s
)
select
DEPARTMENT_ID,
DEPARTMENT_NAME,
StudentCnt
from DepOrdered
where
-- Rnk = 1 would have all departments with max number of students
Rnk > 1

SQL Nested select in From caluse

I am confuse, can we write SELECT statement in FROM clause and if yes why can it be.
SELECT v.employee_id, v.last_name, v.lev
FROM
(SELECT employee_id, last_name, LEVEL lev
FROM employees v
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id) v
WHERE (v.employee_id, v.lev) IN
(SELECT employee_id, 2 FROM employees);
The answer is yes, you can use. The select clause in the from will act as a inline view(consider it as a temporary table that databse creates to hold the results).
For example:
SELECT sdt sdat
FROM (SELECT SYSDATE sdt FROM dual);
In the above query, SELECT SYSDATE sdt FROM dual is executed first, and output would be like:
sdt
---
08-Dec-2016 16:20:56
Then, using this as a temp table(which is called an inline view in such cases), oracle will execute your outer select on this data. Hence SELECT sdt FROM... executes, giving the final output as:
sdat
----
08-Dec-2016 16:20:56
I think you are looking for a recursive cte in sql server which would be something like.....
WITH X (employee_id, last_name, lev )
AS (
SELECT employee_id, last_name, 0 AS lev
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.employee_id, e.last_name , lev + 1
FROM employees e
INNER JOIN x ON x.employee_id = e.manager_id
)
SELECT v.employee_id, v.last_name, v.lev
FROM X
WHERE lev = 2

Oracle Grouping and Duplicate Checking

I've been scratching my head on this one.
This question got me closer but my situation is a little more complex.
How do I find duplicate values in a table in Oracle?
Suppose I have a table EMPLOYEE and I want to know which employees work in multiple departments. My table has the employee id, and department they work in. When an employee works in multiple departments, their employee id will be listed as multiple records. I don't want to just count the employees that are listed twice. I need to know how many work in this list of departments vs this list of departments.
So for example if my table is:
Employee ID | Department
1 Accounting
1 Marketing
2 Accounting
3 Finance
4 Programming
And Department List A is
Accounting
Finance
And Department List B is
Marketing
Programming
Then the results of the query would be
Employee ID | Department
1 Accounting
1 Marketing
or
Employee ID | Count(Department)
1 2
since employee 1 works in a department from List A and List B.
I would approach this with a mapping:
with mapping as (
select 'Accounting' as department, 'A' as grouping from dual union all
select 'Finance' as department, 'A' as grouping from dual union all
select 'Marketing' as department, 'B' as grouping from dual union all
select 'Programming' as department, 'B' as grouping from dual
)
select employeeid, count(distinct m.grouping)
from t join
mapping m
on t.department = m.department
group by employeeid;
Note: you may want to store this information in another table or as an attribute in the Departments table.
If you want solo departments to map to themselves:
select t.employeeid, count(distinct coalesce(m.grouping, t.department))
from t join
mapping m
on t.department = m.department
group by t.employeeid;
If you want other departments not in the table to be grouped together:
select t.employeeid, count(distinct coalesce(m.grouping, 'UNKNOWN MAPPING'))
from t join
mapping m
on t.department = m.department
group by t.employeeid;
If I understand what you're after, you can use conditional aggregation in a HAVING clause for this:
SELECT Employee_ID, COUNT(DISTINCT Department) AS Dept_Count
FROM YourTable
GROUP BY Employee_ID
HAVING MAX(CASE WHEN Department IN ('Accounting','Finance') THEN 1 ELSE 0 END) = 1
AND MAX(CASE WHEN Department IN ('Marketing','Programming') THEN 1 ELSE 0 END) = 1