I am trying to retrieve data from one table and then insert it into another table.
This is a a sample of the first table in which there is the following data. tb1 is the table which consists of data. The two columns Manager and TeamLeader basically means for example : Josh is managed by Vik and so on. An employee can also be a manager to another employer. For example, Josh is the manager of Nirvan and Deva.
+---------+-------------+
| tbl1 |
+---------+-------------+
| Manager | Employee |
+---------+-------------+
| Vik | Josh |
+---------+-------------+
| Vik | Cindy |
+---------+-------------+
| Vik | Alvin |
+---------+-------------+
| Vik | Kim |
+---------+-------------+
| Josh | Nirvan |
+---------+-------------+
| Josh | Deva |
+---------+-------------+
| Cindy | Mervyn |
+---------+-------------+
| Nirvan | Reeta |
+---------+-------------+
| Nirvan | Zaki |
+---------+-------------+
| Nirvan | Sunny |
+---------+-------------+
What i want is to insert all these records in another table with the following columns : Id(which is set to IDENTITY/AUTONUM), Name(name of employee/manager), ParentId(of the manager which a particular employee has to report to).
So for example,
I should be getting something of the sort :
ID Name ParentId
1 Vik 0
2 Josh 1
3 Cindy 1
4 Alvin 1
5 Kim 1
6 Nirvan 2
7 Deva 2
8 Mervyn 3
9 Reeta 6
10 Zaki 6
11 Sunny 6
I am having difficulty to get the right sql to retrieve this data from the first table and insert it into another table.
You have to do it in two steps. One to create all your ID fields. Then you can join with this table to match up the employee to find the manager and the manager's ID:
insert into MyNewTable (Name, ParentID)
select Manager, ParentID
from tbl1
union
select Employee, ParentID
from tbl1
update MyNewTable
set MyNewTable.ParentId = Managers.Id
from MyNewTable
join tbl1
on tbl1.Employee = MyNewTable.Name
join MyNewTable Managers
on MyNewTable.Name = Managers.Manager
INSERT INTO tbl2 (
Name
,parentId
)
SELECT DISTINCT manager
,0
FROM tbl1
WHERE manager NOT IN (
SELECT employee
FROM tbl1
)
INSERT INTO tbl2
SELECT DISTINCT employee
,0
FROM tbl1
UPDATE tbl2
SET parentid = parent.id
FROM tbl2
INNER JOIN tbl1 ON tbl2.Name = tbl1.employee
INNER JOIN tbl2 parent ON parent.Name= tbl1.manager
create table #tbl1 (manager char(15), employee char(15))
create table #tbl2 (ID int identity(1,1), Name char(15), ParentID int)
insert into #tbl1
values ('Vik', 'Josh') ,
('Vik' , 'Cindy') ,
('Vik' , 'Alvin') ,
('Vik' , 'Kim') ,
('Josh' , 'Nirvan'),
('Josh' , 'Deva') ,
('Cindy' ,'Mervyn') ,
('Nirvan' , 'Reeta'),
('Nirvan' , 'Zaki'),
('Nirvan' , 'Sunny')
--- big Boss
insert into #tbl2(Name, ParentID)
SELECT DISTINCT manager, 0
FROM #tbl1
WHERE manager NOT IN ( SELECT employee FROM #tbl1 )
--- Grab all Employees (Name)
insert into #tbl2(Name)
select distinct employee from #tbl1
--- Update ParentID
declare #StructureLevl int = 3 -- 0 1 2 3 Do something to figure out this number first
declare #Var_int int = 0
while (#Var_int < #StructureLevl)
begin
update #tbl2
set ParentID= #Var_int +1
where Name in (select A.employee
from #tbl1 A inner join #tbl2 B on A.manager = B.Name
where B.ParentID = #Var_int)
set #Var_int +=1
end
select * from #tbl2
order by ParentID
Related
I'm relatively new to SQL and currently making some practical tasks to gain experience and got struggled with an update of my custom overview table with values from another table that contains join.
I have an overview table MyTable with column EmployeeID. AnotherTable contains data of employees with EmployeeID and their ManagerID.
I am able to retrieve ManagerName using different join methods, including:
SELECT m.first_name
FROM AnotherTable.employees e LEFT JOIN
AnotherTable.employees m
on m.EmployeeID = e.ManagerID
But I am getting stuck updating MyTable, as I usually receive errors such as "single row query returns more than one row" or "SQL command not properly ended". I've read that Oracle doesnt support joins for updating tables. How can I overcome this issue? A sample data would be:
MyTable
------------------------------
EmployeeID | SomeOtherColumns| ..
1 | SomeData |
2 | SomeData |
3 | SomeData |
4 | SomeData |
5 | SomeData |
------------------------------
OtherTable
-------------------------------------
EmployeeID | Name | ManagerID |
1 | Steve | - |
2 | John | 1 |
3 | Peter | 1 |
4 | Bob | 2 |
5 | Patrick | 3 |
6 | Connor | 1 |
-------------------------------------
And the result would be then:
MyTable
-------------------------------------------
EmployeeID | SomeOtherColumns |ManagerName|
1 | SomeData | - |
2 | SomeData | Steve |
3 | SomeData | Steve |
4 | SomeData | John |
5 | SomeData | Peter |
6 | SomeData | Steve |
-------------------------------------------
As one of the options I tried to use is:
update MyTable
set MyTable.ManagerName = (
SELECT
(m.name) ManagerName
FROM
OtherTable.employees e
LEFT JOIN OtherTable.employees m ON
m.EmployeeID = e.ManagerID
)
But there I get "single row query returns more than one row" error. How is it possible to solve this?
You can use a hierarchical query:
UPDATE mytable m
SET managername = (SELECT name
FROM othertable
WHERE LEVEL = 2
START WITH employeeid = m.employeeid
CONNECT BY PRIOR managerid = employeeid);
or a self-join:
UPDATE mytable m
SET managername = (SELECT om.name
FROM othertable o
INNER JOIN othertable om
ON (o.managerid = om.employeeid)
WHERE o.employeeid = m.employeeid);
Which, for the sample data:
CREATE TABLE MyTable (EmployeeID, SomeOtherColumns, ManagerName) AS
SELECT LEVEL, 'SomeData', CAST(NULL AS VARCHAR2(20))
FROM DUAL
CONNECT BY LEVEL <= 5;
CREATE TABLE OtherTable(EmployeeID, Name, ManagerID) AS
SELECT 1, 'Alice', NULL FROM DUAL UNION ALL
SELECT 2, 'Beryl', 1 FROM DUAL UNION ALL
SELECT 3, 'Carol', 1 FROM DUAL UNION ALL
SELECT 4, 'Debra', 2 FROM DUAL UNION ALL
SELECT 5, 'Emily', 3 FROM DUAL UNION ALL
SELECT 6, 'Fiona', 1 FROM DUAL;
Then after either update, MyTable contains:
EMPLOYEEID
SOMEOTHERCOLUMNS
MANAGERNAME
1
SomeData
null
2
SomeData
Alice
3
SomeData
Alice
4
SomeData
Beryl
5
SomeData
Carol
Note: Keeping this data violates third-normal form; instead, you should keep the employee name in the table with the other employee data and then when you want to display the manager's name use SELECT ... FROM ... LEFT OUTER JOIN with a hierarchical query to include the result. What you do not want to do is duplicate the data as then it has the potential to become out-of-sync when something changes.
db<>fiddle here
I have two tables of 1:m relation. Need to select which People records have both records in Actions table whit id 1 and 2
People
+----+------+--------------+
| id | name | phone_number |
+----+------+--------------+
| 1 | John | 111111111111 |
+----+------+--------------+
| 3 | Jane | 222222222222 |
+----+------+--------------+
| 4 | Jack | 333333333333 |
+----+------+--------------+
Action
+----+------+------------+
| id | PplId| ActionId |
+----+------+------------+
| 1 | 1 | 1 |
+----+------+------------+
| 2 | 1 | 2 |
+----+------+------------+
| 3 | 2 | 1 |
+----+------+------------+
| 4 | 4 | 2 |
+----+------+------------+
Output
+----+------+--------------+----------
|PplId| name | Phone |ActionId |
+-----+------+-------------+----+-----
| 1 | John | 111111111111| 1 |
+-----+------+-------------+----+-----
| 1 | John | 111111111111| 2 |
+-----+------+-------------+----+-----
Return records of People that have both Have Actionid 1 and Action id 2(Have records in Actions).
Window functions are one method. Assuming actions are not duplicated for a person:
select pa.*
from (select p.*, a.action, count(*) over (partition by p.id) as num_actions
from people p join
action a
on p.id = a.pplid
where a.action in (1, 2)
) pa
where num_actions = 2;
In my opinion, getting two rows with the action detail seems superfluous -- you already know the actions. If you only want the people, then exists comes to mind:
select p.*
from people p
where exists (select 1 from actions where a.pplid = p.id and a.action = 1) and
exists (select 1 from actions where a.pplid = p.id and a.action = 2);
With the right index (actions(pplid, action)), I would expect two exists to be faster than group by.
Try this below query using subquery and join
select a.Pplid, name, phone, actionid from (
select a.pplid as Pplid, name, phone_number as phone
from People P
join Action A on a.pplid= p.id
group by a.pplid, name, phone_number
having count(*)>1 )P
join Action A on a.Pplid= p.Pplid
Try something like this
IF OBJECT_ID('tempdb..#People') IS NOT NULL DROP TABLE #People
CREATE TABLE #People (id INT, name VARCHAR(255), phone_number VARCHAR(50))
INSERT #People
SELECT 1, 'John', '111111111111' UNION ALL
SELECT 3, 'Jane', '222222222222' UNION ALL
SELECT 4, 'Jack', '333333333333'
IF OBJECT_ID('tempdb..#Action') IS NOT NULL DROP TABLE #Action
CREATE TABLE #Action (id INT, PplId INT, ActionId INT)
INSERT #Action
SELECT 1, 1, 1 UNION ALL
SELECT 2, 1, 2 UNION ALL
SELECT 3, 2, 1 UNION ALL
SELECT 4, 4, 2
GO
SELECT p.ID AS PplId
, p.name
, p.phone_number AS Phone
, a.ActionId
FROM #People p
JOIN #Action a
ON p.ID = a.PplId
WHERE p.ID IN ( SELECT PplId
FROM #Action
WHERE ActionId IN (1, 2)
GROUP BY PplId
HAVING COUNT(*) = 2 )
AND a.ActionId IN (1, 2)
GO
We have two tables below, I am trying to write a query that will select EVERY Purchase for EVERY person on the team. For example, it should show PersonA being associated to PurchaseID 1 and 2 because they are on the same Team as TeamA.
Is this possible? I thought a cross join would work but it seemed to bring back too many columns. I am running SQL Server.
Thank you
Purchases
| PurchaseID | PersonID |
|------------ |---------- |
| 1 | TeamA |
| 2 | TeamA |
| 3 | PersonA |
| 4 | PersonB |
| 5 | TeamB |
Teams
| TeamID | PersonID |
|-------- |---------- |
| 1 | PersonA |
| 1 | TeamA |
| 1 | PersonC |
| 2 | PersonB |
| 2 | TeamB |
Expected results (when filtered on PurchaseID 1):
| PurchaseID | PersonID |
|------------ |---------- |
| 1 | TeamA |
| 1 | PersonA |
| 1 | PersonC |
Your data structure is a little odd, but I think I understand what you want.
If PersonA made a purchase, and PersonA is on TeamA, then everyone on TeamA should be shown as being associated with the purchase, right? Like "I bought these doughnuts for my team, so everyone on my team gets a doughnut".
What you're going to want is to join Purchase to Team on PersonID, as you probably guessed. But then use a CROSS APPLY function, which is in inline table value function, to return all the people on the same team as the person in the "current row".
I used two common table expressions to represent your tables so I could run it. You'll just want the SELECT part:
with Purchases as (
select 1 as PurchaseID, 'TeamA' as PersonID
union select 2 as PurchaseID, 'TeamA' as PersonID
union select 3 as PurchaseID, 'PersonA' as PersonID
union select 4 as PurchaseID, 'PersonB' as PersonID
union select 5 as PurchaseID, 'TeamB' as PersonID
)
, Teams as (
select 1 as TeamID, 'PersonA' as PersonID
union select 1 as TeamID, 'TeamA' as PersonID
union select 1 as TeamID, 'PersonC' as PersonID
union select 2 as TeamID, 'PersonB' as PersonID
union select 2 as TeamID, 'TeamB' as PersonID
)
select Purchases.PurchaseID
, EveryTeamMember.PersonID
from Purchases
join Teams
on Teams.PersonID = Purchases.PersonID
cross apply (
select PersonID
from Teams InnerTable
where InnerTable.TeamID = Teams.TeamID
) as EveryTeamMember
where Purchases.PurchaseID = 1
If you are looking ti get all Team persons when the PersonID starts with Team then i think you should do a CROSS APPLY over all PersonID who starts with Team and UNION (NOT UNION ALL) Single Person purchases:
DECLARE #Purchases TABLE (
PurchaseID INT,
PersonID Varchar(50)
)
INSERT INTO #Purchases(PersonID,PurchaseID) VALUES ('TeamA', 1);
INSERT INTO #Purchases(PersonID,PurchaseID) VALUES ('TeamA', 2);
INSERT INTO #Purchases(PersonID,PurchaseID) VALUES ('PersonA', 3);
INSERT INTO #Purchases(PersonID,PurchaseID) VALUES ('PersonB', 4);
INSERT INTO #Purchases(PersonID,PurchaseID) VALUES ('TeamB', 5);
DECLARE #Teams TABLE (
TeamID INT,
PersonID Varchar(50)
)
INSERT INTO #Teams(PersonID,TeamID) VALUES ('PersonA', 1);
INSERT INTO #Teams(PersonID,TeamID) VALUES ('TeamA', 1);
INSERT INTO #Teams(PersonID,TeamID) VALUES ('PersonC', 1);
INSERT INTO #Teams(PersonID,TeamID) VALUES ('PersonB', 2);
INSERT INTO #Teams(PersonID,TeamID) VALUES ('TeamB', 2);
SELECT T1.PurchaseID,TeamPersons.PersonID
FROM #Purchases T1
INNER JOIN #Teams T2
ON T2.PersonID = T1.PersonID AND T1.PersonID LIKE'Team%'
CROSS APPLY (
SELECT PersonID
FROM #Teams T3
WHERE T3.TeamID = T2.TeamID
) AS TeamPersons
UNION
SELECT T1.PurchaseID
, T1.PersonID
FROM #Purchases T1
WHERE T1.PersonID NOT LIKE 'Team%'
Result
I have a table having data as below.
Say I have two versions of the project and I need to migrate data from older version to a new version.
Let's say tblFolders in version1
+----+------------+--------------+--------------+
| id | FolderName | CreatedBy | ModifiedBy |
+----+------------+--------------+--------------+
| 1 | SIMPLE | 5 | 6 |
| 2 | SIMPLE1 | 8 | 1 |
+----+------------+--------------+--------------+
And another table having userid of both versions.
Let's say its tblUsersMapping
+----+----------------+-------------------+
| id | Version1UserID | Version2UserID |
+----+----------------+-------------------+
| 1 | 1 | 500 |
| 2 | 2 | 465 |
| 3 | 3 | 12 |
| 4 | 4 | 85 |
| 5 | 5 | 321 |
| 6 | 6 | 21 |
| 7 | 7 | 44 |
| 8 | 8 | 884 |
+----+----------------+-------------------+
Now I need to transfer data from version 1 to version 2. When I transferring data, CreatedBy and Modifiedby ids should by of the new version.
So though I have data as below
| 1 | SIMPLE | 5 | 6 |
It should be transferred as below
| 1 | SIMPLE | 321 | 21 |
For that, I have added a join so far between these two tables as below.
SELECT id,
foldername,
B.version2userid AS CreatedBy
FROM tblfolders A WITH(nolock)
LEFT JOIN tblusersmapping B WITH(nolock)
ON A.createdby = B.version1userid
This would give me a proper result for column CreatedBy.
But how can I get userid from tblUsersMapping for ModifiedBy column?
Doing below will not work and will give NULL for both the columns.
SELECT id,
foldername,
b.version2userid AS createdby,
b.version2userid AS modifiedby
FROM tblfolders A WITH(nolock)
LEFT JOIN tblusersmapping B WITH(nolock)
ON a.createdby = b.version1userid,
a.modifiedby = b.version1userid
One way is I can add another join with tblusersmapping table. But its not a good idea because tables can have a huge data and another join will affect the performance of the query.
My question is how can I get Version1UserID and Version2UserID from mapping table based on createdby and modifiedby columns?
You can use multiple select which may help you.
SELECT id,
foldername,
(SELECT version2userid from tblUsersMapping where Version1UserID=tblfolders.CreatedBy) AS CreatedBy,
(SELECT version2userid from tblUsersMapping where Version1UserID=tblfolders.ModifiedBy) AS ModifiedBy
FROM tblfolders
If you want to populate both the column where each column joins to to a different row, in that case you have to join the same table twice like following. You can't get it with a single table join the way you are expecting.
SELECT id,
foldername,
B.version2userid AS CreatedBy
C.Version2UserID AS ModifiedBy
FROM tblfolders A WITH(nolock)
LEFT JOIN tblusersmapping B WITH(nolock)
ON A.createdby = B.version1userid
LEFT JOIN tblusersmapping C WITH(nolock)
ON A.ModifiedBy = C.version1userid
Try this, it will work across all sample data,
select tf.id,tf.FolderName
,oa.Version2UserID as CreatedBy
,oa1.Version2UserID as ModifiedBy
from #tblFolders tf
outer apply(select top 1 Version2UserID
from #tblUsersMapping tu
where tu.Version1UserID= tf.CreatedBy order by id desc)oa
outer apply(select top 1 Version2UserID
from #tblUsersMapping tu
where tu.Version1UserID= tf.ModifiedBy order by id desc)oa1
You can use UDF to return modifiedby and INNER JOIN instead of LEFT JOIN (if requirement meets) as below. I think it will help in the preformance
CREATE TABLE tblFolders (id INT, folderName VARCHAR(20), createdBy INT, modifiedBy INT)
INSERT INTO tblFolders VALUES
(1,'SIMPLE', 5,6),
(2,'SIMPLE1', 8,1)
CREATE TABLE tblUsersMapping(id INT, Version1UserID INT, Version2UserID INT)
INSERT INTO tblUsersMapping VALUES
(1,1,500),
(2,2,465),
(3,3,12),
(4,4,85),
(5,5,321),
(6,6,21),
(7,7,44),
(8,8,884)
SELECT a.id,
a.foldername,
b.version2userid AS createdby,
dbo.FNAReturnModifiedBy(a.modifiedBy) AS modifiedby
FROM tblfolders A WITH(nolock)
INNER JOIN tblusersmapping B WITH(nolock) ON a.createdby = b.version1userid
--Function
IF OBJECT_ID(N'dbo.FNAReturnModifiedBy', N'FN') IS NOT NULL
DROP FUNCTION dbo.FNAReturnModifiedBy
GO
CREATE FUNCTION dbo.FNAReturnModifiedBy(#updated_by INT)
RETURNS INT AS
BEGIN
DECLARE #updateUserID INT
SELECT #updateUserID = Version2UserID
FROM tblusersmapping WHERE Version1UserID = #updated_by
RETURN #updateUserID
END
OUTPUT:
id foldername createdby modifiedby
1 SIMPLE 321 21
2 SIMPLE1 884 500
Note :
I did not know about how to find the query performance. I wrote only for your expected output.
I am using SQL Server 2012.
I did not use more than one Join.
Query did JOIN, GROUP BY, ROW_NUMBER (), CASE instead of two LEFT JOIN
Input :
create table ##ver (id int, FolderName varchar (10), CreatedBy int, ModifiedBy int)
insert into ##ver values
(1,'SIMPLE',5,6)
,(2,'SIMPLE1',8,1)
,(3,'File',7, 5)
select * from ##ver
create table ##veruser (id int, Version1UserID int, Version2UserID int)
insert into ##veruser values
(1 , 1 , 500)
,(2 , 2 , 465)
,(3 , 3 , 12 )
,(4 , 4 , 85 )
,(5 , 5 , 321)
,(6 , 6 , 21 )
,(7 , 7 , 44 )
,(8 , 8 , 884)
select * from ##veruser
Query :
select
id, FolderName
, max (case when rn = 1 then Version2UserID end) Version1UserID
, max (case when rn = 2 then Version2UserID end) Version2UserID
from (
select
v.id, v.FolderName, u.Version1UserID, u.Version2UserID
, ROW_NUMBER () over
(partition by v.id order by v.id, v.CreatedBy,
case
when v.CreatedBy > v.ModifiedBy then u.Version1UserID
end desc
) rn
, v.CreatedBy, v.ModifiedBy
from ##ver v
join ##veruser u
on u.Version1UserID in (v.CreatedBy, v.ModifiedBy)
) a
group by id, FolderName
order by id
Update 1:
Query does :
Join the tables.
Row numbering, over (),
Partition by Id.
Order by File id (v.id), Creator id ascending, If creator id greater
than modified id, then creator id descending. (Due to second step this reordering is must)
Depends on 'rn' values, rows are transfer to columns
(You can find many examples at here)
Output :
id FolderName Version1UserID Version2UserID
1 SIMPLE 321 21
2 SIMPLE1 884 500
3 File 44 321
Try this one.
Select a.id,folderName,b.Version2UserId as createdby,c.Version2UserId as modifiedby
from tblFolders as a WITH(nolock)
inner join tblUsersMapping as b WITH(nolock) on a.createdby =b .Version1UserID
inner join tblUsersMapping as c WITH(nolock) on a.modifiedBy =c .Version1UserID
This question has 2 parts.
Part 1
I have a table "Groups":
group_ID person
-----------------------
1 Person 10
2 Person 11
3 Jack
4 Person 12
Note that not all data in the "person" column have the same format.
In SQL Server, I have used the following query to strip the "Person " characters out of the person column:
SELECT
REPLACE([person],'Person ','')
AS [person]
FROM Groups
I did not use UPDATE in the query above as I do not want to alter the data in the table.
The query returned this result:
person
------
10
11
12
However, I would like this result instead:
group_ID person
-------------------
1 10
2 11
3 Jack
4 12
What should be my query to achieve this result?
Part 2
I have another table "Details":
detail_ID group1 group2
-------------------------------
100 1 2
101 3 4
From the intended result in Part 1, where the numbers in the "person" column correspond to those in "group1" and "group2" of table "Details", how do I selectively convert the numbers in "person" to integers and join them with "Details"?
Note that all data under "person" in Part 1 are strings (nvarchar(100)).
Here is the intended query output:
detail_ID group1 group2
-------------------------------
100 10 11
101 Jack 12
Note that I do not wish to permanently alter anything in both tables and the intended output above is just a result of a SELECT query.
I don't think first part will be a problem here. Your query is working fine with your expected result.
Schema:
CREATE TABLE #Groups (group_ID INT, person VARCHAR(50));
INSERT INTO #Groups
SELECT 1,'Person 10'
UNION ALL
SELECT 2,'Person 11'
UNION ALL
SELECT 3,'Jack'
UNION ALL
SELECT 4,'Person 12';
CREATE TABLE #Details(detail_ID INT,group1 INT, group2 INT);
INSERT INTO #Details
SELECT 100, 1, 2
UNION ALL
SELECT 101, 3, 4 ;
Part 1:
For me your query is giving exactly what you are expecting
SELECT group_ID,REPLACE([person],'Person ','') AS person
FROM #Groups
+----------+--------+
| group_ID | person |
+----------+--------+
| 1 | 10 |
| 2 | 11 |
| 3 | Jack |
| 4 | 12 |
+----------+--------+
Part 2:
;WITH CTE AS(
SELECT group_ID
,REPLACE([person],'Person ','') AS person
FROM #Groups
)
SELECT D.detail_ID, G1.person, G2.person
FROM #Details D
INNER JOIN CTE G1 ON D.group1 = G1.group_ID
INNER JOIN CTE G2 ON D.group1 = G2.group_ID
Result:
+-----------+--------+--------+
| detail_ID | person | person |
+-----------+--------+--------+
| 100 | 10 | 10 |
| 101 | Jack | Jack |
+-----------+--------+--------+
Try following query, it should give you the desired output.
;WITH MT AS
(
SELECT
GroupId, REPLACE([person],'Person ','') Person
AS [person]
FROM Groups
)
SELECT Detail_Id , MT1.Person AS group1 , MT2.Person AS AS group2
FROM
Details D
INNER JOIN MT MT1 ON MT1.GroupId = D.group1
INNER JOIN MT MT2 ON MT2.GroupId= D.group2
The first query works
declare #T table (id int primary key, name varchar(10));
insert into #T values
(1, 'Person 10')
, (2, 'Person 11')
, (3, 'Jack')
, (4, 'Person 12');
declare #G table (id int primary key, grp1 int, grp2 int);
insert into #G values
(100, 1, 2)
, (101, 3, 4);
with cte as
( select t.id, t.name, ltrim(rtrim(replace(t.name, 'person', ''))) as sp
from #T t
)
-- select * from cte order by cte.id;
select g.id, c1.sp as grp1, c2.sp as grp2
from #G g
join cte c1
on c1.id = g.grp1
join cte c2
on c2.id = g.grp2
order
by g.id;
id grp1 grp2
----------- ----------- -----------
100 10 11
101 Jack 12