List records from a chosen employee to the ultimate manager - sql

Given the following Table (In Postgres):
EmployeeID
EmployeeName
ManagerID
1
David
NULL
2
Jessica
NULL
3
Gregg
1
4
Joe
3
5
Brandon
NULL
6
Leslie
4
7
Harry
6
8
Paul
NULL
9
Frank
5
Starting from Employee ID 7 (Harry) - how do I list only the records, bottom-up, in the hierarchy until I get to the ultimate manager (which should be David, in this case)? Should I use recursive CTE? If so, how does that query look?
Expected Output:
EmployeeID
EmployeeName
ManagerID
1
David
NULL
3
Gregg
1
4
Joe
3
6
Leslie
4
7
Harry
6

In the common table expression, you can recognize:
the base step, where you select the record relatively to employee no 7
the recursive step, where you match managers with currently retrieved employees.
The recursion stops when the INNER JOIN does not return any more extra record.
WITH RECURSIVE cte AS (
SELECT * FROM tab WHERE EmployeeID = 7
UNION ALL
SELECT mgr.*
FROM cte emp
INNER JOIN tab mgr
ON emp.ManagerID = mgr.EmployeeID
)
SELECT *
FROM cte
Check the demo here.

Related

SQL for joining two tables and grouping by shared column

I want to join two tables and use the column they both share to group the results, including a null result for those accountIds which only appear in one table.
Table a
AccountId
productApurchases
Steve
1
Jane
5
Bill
10
Abed
2
Table b
AccountId
productApurchases
Allan
1
Jane
10
Bill
2
Abed
1
Mike
2
Desired output
AccountId
productApurchases
productBpurchases
Steve
1
0
Jane
5
10
Bill
10
2
Abed
2
1
Mike
0
2
I've been trying with various joins but cannot figure out how to group by all the account ids.
Any advice much appreciated, thanks.
Use full join:
select accountid,
coalesce(productApurchases, 0) as productApurchases,
coalesce(productBpurchases, 0) as productBpurchases
from a full join
b
using (accountid);

SQL query to identify result using self join or any other way

Suppose I have a table like below:
ID Name ManagerID
1 Dave NULL
2 Scott 1
3 Mike 1
4 Nick 3
5 Jack 1
How Can I find out corresponding Manager Name of all the employee, something like below format?
ID Name ManagerID ManagerName
1 Dave NULL NULL
2 Scott 1 Dave
3 Mike 1 Dave
4 Nick 3 Mike
5 Jack 1 Dave
Try this!
select a.ID,a.Name,a.ManagerID,b.Name as ManagerName
from #t a left join #t b on a.ManagerID=b.ID
Demo
select ID, Name, ManagerID,
(case when managerid is null then null else (select Name from tab where id=managerid) end) as ManagerName
from tab
You can do this way too
Possible in several ways.
Such as:
SELECT
ID, Name, ManagerID,
(SELECT Name FROM table AS ManagersTable WHERE ManagersTable.ID=EmployeesTable.ManagerID) AS ManagerName
FROM table AS EmployeesTable

Querying 100k records to 5 records

I have a requirement in such a way that it should join two tables with more than 100k records in one table and just 5 records in another table as shown below
Employee Dept Result
id Name deptid deptid Name Name deptid Name
1 Jane 1 1 Science Jane 1 Science
2 Jack 2 2 Maths Dane 1 Science
3 Dane 1 3 Biology Jack 2 Maths
4 Drack 3 4 Social Drack 3 Biology
5 Drim 5 Zoology Kery 4 Social
6 Drum 5 Drum 5 Zoology
7 Krack
8 Kery 4
.
.
100k
Which join need to be used to get the query in an better way to perform to get the result as shown.
I just want the query to join with other table from employee table only which has dept which i thought of below query but wanted to know is there any better way to do it.
Select e.name,d.deptid,d.Name from
(Select deptid,Name from Employee where deptid IS NOT NULL) A
and dept d where A.deptid=d.deptid;
Firstly not sure why you are performing your query the way you are. Should be more like
SELECT A.name, D.deptid,D.Name
FROM Employee A
INNER JOIN dept D
ON A.deptid = D.deptid
No need of the IS NOT NULL statement.
If this is a ONE TIME or OCCASIONAL thing and performance is key (not a permanent query in your DB) you can leave out the join altogether and do it using CASE:
SELECT
A.name, A.deptid,
CASE
WHEN A.deptid = 1 THEN "Science"
WHEN A.deptid = 2 THEN "Maths"
...[etc for the other 3 departments]...
END as Name
FROM Employee A
If this is to be permanent and performance is key, simply try applying an INDEX on the foreign key deptid in the Employee table and use my first query above.

Select unique random posting/recruitment places of employees within a list of places

I am trying to select unique random posting/recruitment places of employees within a list of places, all the employees are already posted at the places, i am trying to generate a new random posting place for them with "where" condition that "employee new random location will not be equal to their home place"
Employee table is :
EmpNo Empname CurrentPosting Home Designation RandomPosting
1 Satish Kumar Samastipur Gazi Manager
2 Anil Kumar Singh Vaishali Patna Manager
3 Rajdev Prasad Nawada Gaya PO
4 Rajesh Kumar Sheikhpura Muzaffarpur PO
5 Jitendra Kumar Banka Bhagalpur Clerk
And so on...
And Places table is
PlaceID PlaceName Manager PO Clerk
1 Araria 2 0 1
2 Arwal 1 1 1
3 Aurangabad 1 0 2
4 Banka 2 1 1
5 Begusarai 1 1 1
6 Bhagalpur 1 1 2
7 Bhojpur 0 2 0
and so on...
i tried with rand() and newid() like as below,
select Employee.*, Place.PlaceName As RandomPosting from Employee
inner join Place on Place.PlaceID=Employee.EmpNo order by newid()
But unable to select what is required... that is to assign each Employee a PlaceName(from Place) randomly which is not equal to CurrentPosting and Home(in Employee).
Thanks in advance.
WITH cteCrossJoin AS (
SELECT e.*, p.PlaceName,
ROW_NUMBER() OVER(PARTITION BY e.EmpNo ORDER BY NEWID()) AS RowNum
FROM Employee e
CROSS JOIN Place p
WHERE e.Home <> p.PlaceName
)
SELECT *
FROM cteCrossJoin
WHERE RowNum = 1;

Joining data from 2 tables

I'm working on the adventureworks example database.
I have a table with employee's, which all have a certain manager. So in the table employee's there is a column ManagerID.
Also in the table employee there's a ContactID, which contains the name of that employee.
I would like to have a list with all the managers and their names. How can I pull this off?
The table looks something like
EmployeeID ContactID ManagerID
---------- --------- ---------
1 21 4
2 24 4
3 32 7
4 34 2
5 35 2
6 42 7
7 44 4
So i'll need a DISTINCT list of the managerID, and then search for each managerID their appropreate ContactID.
So:
manager of employee 1 is Employee 4 with the ContactID 34.
manager of employee 3 is Employee 7 with the ContactID 44.
manager of employee 4 is Employee 2 with the ContactID 24.
Thanks.
You can do it joining the table myTable with itself matching manager_id's with employee_id's
select
t.employeeid as employee_id,
t.manager_id as manager_id,
t2.contact_id as manager_contact_id
from mytable t left outer join mytable t2 on t.managerid = t2.employeeid
SELECT ManagerID, EmployeeID, ConactID
FROM ´yourtable´
GROUP BY ManagerID
There you get the grouped data.
If you want to have Managers listed as well you have to JOIN the data again (self-join)