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

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

Related

List records from a chosen employee to the ultimate manager

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.

How to select distinct column once and blank to its similar id column

I want result like
Dept Name EmployeeCount
IT Ankit 4
Aman 4
Rakesh 4
Rohhit 4
HR Deepak 3
Manoj 3
Raj 3
You may use window function here -
SELECT CASE WHEN Dept = LAG(Dept) OVER() THEN NULL ELSE Dept END Dept
,Name
,COUNT(Name) OVER() EmployeeCount
FROM YOUR_TABLE;

T-SQL - Concatenate Multiple Rows

I am struggling with a query to return a list of managers with their respective employees
I have three tables as follows:
Managers
ManagerID ManagerName
1 Bob
2 Sally
3 Peter
4 George
EmployeeManager
EmployeeID ManagerID
1 1
1 1
2 2
2 2
3 3
3 3
4 4
4 4
Employees
EmployeeID EmployeeName
1 David
1 Joseph
2 Adam
2 Pete
3 Mark
3 Mavis
4 Susan
4 Jennifer
Desired Result Set
ManagerName CountEmployee Employees
Bob 2 David, Joseph
Sally 2 Anish, Pete
Peter 2 Mark, Mavis
George 2 Susan, Jennifer
The query I am currently using is as follows:
Select m.ManagerName
,Count(e.EmployeeName) Over(Partition By m.ManagerID) as CountEmployee
,Rank() Over(Partition By m.ManagerID Order By em.EmployeeID) [RankEmployee]
,e.EmployeeName
From dbo.Employees e
Left Join dbo.EmployeeManager em on em.ManagerID=e.ManagerID
Left Join dbo.Managers m on m.ManagerID=em.ManagerID;
This returns a list of managers and employees on individual rows but I'm struggling to concatenate the employee names as per the above table.
Any ideas or solutions?
Manpaal Singh
You can stuff the result to comma seperated result.
Select m.ManagerName
,Count(e.EmployeeName) Over(Partition By m.ManagerID) as CountEmployee
,Rank() Over(Partition By m.ManagerID Order By em.EmployeeID) [RankEmployee]
,STUFF((SELECT ',' + e.EmployeeName
FOR XML PATH('')), 1, 1, '') AS EmployeeName
From dbo.Employees e
Left Join dbo.EmployeeManager em on em.ManagerID=e.ManagerID
Left Join dbo.Managers m on m.ManagerID=em.ManagerID
SELECT M.ManagerName, E.EmployeeName
FROM Managers AS M
INNER JOIN EmployeeManager AS EM ON M.ManagerID = EM.ManagerID
INNER JOIN Employees AS E ON EM.EmployeeID = E.EmployeeID
ORDER BY M.ManagerName
This will give a list of managers and their employees.
when you fix the ID's of the employees table.
1 David
1 Joseph
2 Adam
2 Pete
3 Mark
3 Mavis
4 Susan
4 Jennifer
should be:
1 David
2 Joseph
3 Adam
4 Pete
5 Mark
6 Mavis
7 Susan
8 Jennifer
you can use recursive sql to convert rows in a string :
with t1 (mngId, empName) as (
select a.mngId,
b.empname
from manager as a, employee as b
where b.mngId = a.mngId),
t2 (mngID, nbr, empName, all_name) as (
select mngId,
cast(1 as Int),
min(empName),
cast(min(empName) as varchar(1000)
from t1
group by mngId
union all
select b.mngId,
b.nbr+1,
a.empName,
trim(b.all_name) concat ', ' concat a.empName
from t0 as a, t1 as b
where b.mngId = a.mngId
and a.empName > b.empName
and a.empName = (
select min( c.empName)
from t0 as c
where c.mngId = b.mngId
and c.empName > b.empName )
)
select *
from t1 as e
where nbr = (
select max(nbr)
from t1 as d
where d.mngId = e.mngId )

SQL subquery or not?

I am trying to find a query that will select from two tables but not join those two tables as I don't want the result on one line.
Lets say I have these tables:
Persons1 Persons2
Number Name Surname Number Name Surname
----------------------- -------------------------
1 Peter Miller 1 Frank Farian
2 Hans Geige 2 Thomas Müller
And when I use this query:
SELECT
NEW.NAME,
OLD.NAME
FROM
PERSONS1 NEW,
PERSONS2 OLD
WHERE
NEW.Number = 1 AND
OLD.Number = 1
I get the following result:
Peter Frank
How do I write the query to get:
Peter
Frank
Use UNION for this:
SELECT NEW.NAME
FROM PERSONS1 NEW
WHERE NEW.Number = 1
UNION
SELECT OLD.NAME
FROM PERSONS2 OLD
WHERE OLD.Number = 1

SQL: View Full Name From User ID (Send To / Send From)

I have the following tables:
Students
StudentID UserID FirstName LastName
1 1 John Doe
2 3 Peter Pan
3 5 Mark Twain
Employees
EmployeeID UserID FirstName LastName
1 2 Juan Carlos
2 4 Joe Reyes
3 6 Ash Ketchum
Users
UserID Username
1 test1
2 test2
3 test3
4 test4
5 test5
6 test6
Messages
MessageID MessageFrom MessageTo Subject
1 1 2 test message
2 4 3 another test message
3 3 5 another test message
I want to display the output like this
MessageID MessageFrom MessageTo Subject
1 John Doe Juan Carlos test message
2 Joe Reyes Peter Pan another test message
3 Peter Pan Mark Twain another test message
Where MessageFrom and MessageTo returns a foreign key value from UserID located from the Users table. Students can send messages to the employees, and vice-versa. They can also send between students and employees.
I think this is The X Y Problem again.
Why did you split your Users in two parts ?
Why not making it like this (which would solve the whole problem) :
UserID | FirstName | LastName | UserName | Type
-------------------------------------------------------
1 John Doe test1 1
2 Juan Carlos test2 2
3 Mark Twain test3 1
And add a table Types
TypeId | TypeName
1 Students
2 Employees
This way you have 2 Tables for users instead of 3.
All users and names are in the same table as it should be.
This should do the trick, since you don't care if the message is related to a student or employee you can just union those 2 tables.
SELECT
MessageID,
(FromTable.FirstName + ' ' + FromTable.LastName) AS MessageFrom,
(ToTable.FristName + ' ' + ToTable.LastName) AS MessageTo,
Subject
FROM
Messages
INNER JOIN
(
(SELECT UserID, FirstName, LastName FROM Students)
UNION
(SELECT UserID, FirstName, LastName FROM Employees)
) AS FromTable ON FromTable.UserID = Messages.MessageFrom
INNER JOIN
(
(SELECT UserID, FirstName, LastName FROM Students)
UNION
(SELECT UserID, FirstName, LastName FROM Employees)
) AS ToTable ON ToTable.UserID = Messages.MessageTo