Recursive Manager/Associate query in T/SQL - tsql

looking at this example link
I want to be able to walk through an HR table that I populate with who the manager is that is looking up themself and their reports (which shows them what level they are also)
Data:
AssociateID AssociateName ManagerID AssociateTitle
=========== ============= ========= ==============
1 Jack Frost Chief Executive Officer
2 Cindy Smith 1 President of Sales
3 William Howard 1 President of Technology
4 Ben Samson 2 Director of Tradeshow
5 Sarah Jones 2 Director of Documentation
6 Laurie Ralph 4 Manager
7 Tina Nelson 5 Manager
8 Joe May 6 Coordinator
9 Peter Gill 7 Coordinator
10 Kelly Kraft 2 Director of Facilities
11 Heidi Trump 8 Administrative Assistant
If CEO signs in he gets the following data:
Jack Frost
Cindy Smith
Ben Samson
Laurie Ralph
Joe May
Heidi Trump
William Howard
But if Cindy Smith signs in her list would be:
Cindy Smith
Ben Samson
Laurie Ralph
Joe May
Heidi Trump
The indenting is for visual. I was also wondering if there could be a column that indicates what level the people are below. Level 1; Level 2; etc
And if a person who signs in (example: Heidi Trump) her list is only her name.
Is this possible with TSQL?

I have it and want to share:
DECLARE #Associate float
Set #Associate = 1
;
WITH DirectReports(ManagerID, EmployeeID, Associate, Title, EmployeeLevel) AS
(
SELECT ManagerID, AssociateID, LegalLastName + ', ' + LegalFirstName, Title, 1 AS EmployeeLevel
FROM AssociateMaster
WHERE
ManagerID = #Associate
UNION ALL
SELECT e.ManagerID, e.AssociateID, e.LegalLastName + ', ' + e.LegalFirstName, e.Title, EmployeeLevel + 1
FROM dbo.AssociateMaster AS e
INNER JOIN DirectReports AS d
ON e.ManagerID = d.EmployeeID
)
SELECT
DR.ManagerID, MGR.LegalLastName + ', ' + MGR.LegalFirstName AS AssociateName, DR.EmployeeID, DR.Associate, DR.Title, DR.EmployeeLevel
FROM DirectReports DR
INNER JOIN AssociateMaster as Mgr ON DR.ManagerID = Mgr.AssociateID
UNION
SELECT ' ', ' ', AssociateID, LegalLastName + ', ' + LegalFirstName, Title, 0
FROM AssociateMaster
WHERE
AssociateID = #Associate
ORDER BY
DR.EmployeeLevel Asc,
MGR.LegalLastName + ', ' + MGR.LegalFirstName ASC,
DR.Associate Asc
OPTION (MAXRECURSION 0);

Related

Hibernate Native Query Left Join vs Postgresql Left join (Why are they different)

I'd like to start by saying that I'd like to think I am pretty proficient sql (10 years of experience) and have ran into a head scratcher. I have the following data
Group
Id Name
1 Group 1
2 Group 2
User
Id Name
1 Jon Williams
2 Mike Williams
3 Joyce Copper
Product
Id Name
1 Cookies
2 Milk
3 Ice cream
Status
Id Name
1 Untouched
2 Consumed
3 Partly Consumed
HouseholdProduct
Id Product User Status
1 1 1 1
2 2 2 1
3 3 3 1
4 1 1 1
5 2 2 1
6 3 3 1
GroupHousehold
GroupId HouseholdProductId
1 1
1 2
1 3
2 1
2 2
2 3
In Postgres, I wrote the following
select g.id as Group Id, g.name as Group, p.name as Product,
u.name as User
from group g
left join GroupHouse gh on
g.id = gh.groupId
left join HouseHoldProduct hp on
gh.houseHoldProductId = hp.id
left join User u on
hp.userId = u.Id
left join Product p on
hp.product_id = p.id
order by g.id asc
I get the following data which is correct:
ID Group Product User
1 Group 1 Cookies Jon Williams
1 Group 1 Milk Mike Williams
1 Group 1 Ice cream Joyce Copper
2 Group 2 Cookies Jon Williams
2 Group 2 Milk Mike Williams
2 Group 2 Ice cream Joyce Copper
When I take that exact query and paste it in Hibernate as native query, I get the follow results which is wrong.
ID Group Product User
1 Group 1 Cookies Jon Williams
1 Group 1 Milk Jon Williams
1 Group 1 Ice cream Jon Williams
2 Group 2 Cookies Jon Williams
2 Group 2 Milk Jon Williams
2 Group 2 Ice cream Jon Williams
It looks like hibernate is the left joining to the User table incorrectly. Does anyone know why this is happening? Is there a way to fix this?

Postgresql: two columns the same but third column different, display rows

I have 4 columns id, firstname, last name, reference. Most times the reference is the same but I need to display each row that has the same names, but a different reference in postgresql and order them by the id number. ONLY for those rows which someone has more than one reference. I've tried a bunch of things but just made a mess. Please assist.
For example:-
20 / John / Smith / 675
21 / John / Smith / 675
22 / John / Smith / 676
22 / Joe / Bloggs/ 651
24 / Joe / Bloggs/ 651
25 / John / Smith / 674
Should return all the John Smith rows, because one or more of his references is dissimilar
20 / John / Smith / 675
21 / John / Smith / 675
22 / John / Smith / 676
25 / John / Smith / 674
I can use this to get a count, but I want to display the full rows
select firstname, lastname, count (distinct id)
from transfer
group by firstname, lastname
having count(distinct id) >= 2
You don't need to count, you only have to check if (at least) one record with a different value for reference for the same person exists:
SELECT *
FROM transfer t
WHERE EXISTS (
SELECT * FROM transfer x
WHERE x.firstname = t.firstname -- same name
AND x.lastname = t.lastname
AND x. reference <> t.reference -- different reference
);
This is a possible answer:
select id, firstname, lastname, reference
from transfer t1
where 1 < (select count(distinct reference)
from transfer t2
where t1.firstname = t2.firstname and t1.lastname = t2.lastname)

Using self joins sql query

I have a Table, TEmployee where SequenceId, Date, EmplId, ExtnNumber, FName are the attributes, where SequenceId is unique and there will be multiple entries for same EmplId like
1 1/1/2014 55323 8793 Ryan
2 1/2/2014 83723 9898 Roy
3 1/1/2014 88838 8823 Mark
4 1/2/2014 83723 9832 Roy
5 1/3/2014 32323 2223 Tina
6 1/1/2014 55323 8744 Ryan
select * from TEmployee where EmplId in ('55323','83723') with urlists me the following..
1 1/1/2014 55323 8793 Ryan
2 1/2/2014 83723 9898 Roy
4 1/2/2014 83723 9832 Roy
6 1/1/2014 55323 8744 Ryan
But, i want to list the latest entry to be displayed.. by latest i mean SequenceId.. only entries 4 & 6..
Any pointers would be of good help. Thanks in Advance.
#Jimmy Smith beat me to it with a correct answer, but mine is a correlated subselect, so there is no need to repeat the EMPLID IN ('55323', '83723') part.
SELECT *
FROM TEMPLOYEE AS A
WHERE EMPLID IN ('55323', '83723')
AND SEQUENCEID = (
SELECT MAX(SEQUENCEID)
FROM TEMPLOYEE AS B
WHERE A.EMPLID = B.EMPLID
)
WITH UR
One method may be via a subquery,
select * from TEmployee where EmplId in ('55323', '83723') and SequenceId in (Select Max(SequenceId) where EmplId in ('55323', '83723'))

Return all records regardless if there is a match

In my Table 1, It may have AND have a null entry in the address column to corresponding record OR not have a matching entry in Table 2.
I want to present all the records in Table 1 but also present corresponding entries from Table 2. My RESULT is what I am trying to achieve.
Table 1
ID First Last
1 John Smith
2 Bob Long
3 Bill Davis
4 Sam Bird
5 Tom Fenton
6 Mary Willis
Table 2
RefID ID Address
1 1 123 Main
2 2 555 Center
3 3 626 Smith
4 4 412 Walnut
5 1
6 2 555 Center
7 3
8 4 412 Walnut
Result
Id First Last Address
1 John Smith 123 Main
2 Bob Long 555 Center
3 Bill Davis 626 Smith
4 Sam Bird 412 Walnut
5 Tom Fenton
6 Mary Willis
You need an outer join for this:
SELECT * FROM Table1 t1 LEFT OUTER JOIN Table2 t2 ON t1.ID = t2.RefID
How do you join those two tables? If table 2 have more than 1 matched address, how do you want display them? Please clarify in your question.
Here is a query based on my assumptions.
SELECT
ID, First, Last,
Address = (SELECT MAX(Address) FROM Table2 t2 WHERE t1.ID = t2.ID)
FROM Table1 t1

Counting the size of a group in T-sql

I'd like to count the size of a group.
My table looks like that:
Name Number
Renee Scott 1
Bruno Cote 1
Andree Scott 2
Renee Scott 2
Pierre Dion 2
Pierre Dion 3
Louise Tremblay 3
Renee Scott 3
Andree Scott 3
Jean Barre 3
Bruno Cote 3
There are 2 Name associated with the Number 1, 3 Name with Number 2 and 6 Name with 3. I'd like to select this table where the Number is associated with 3 name or more.
Thank you.
SELECT * FROM TABLENAME WHERE NUMBER IN
(
SELECT NUMBER FROM TABLENAME GROUP BY NUMBER HAVING COUNT(*)>3
)