hopefully someone can help with this. I have recieved a table of data which I need to restructure and build a Denorm table out of. The table structure is as follows
UserID Logon ParentID
2344 Test1 2000
2345 Test2 2000
The issue I have is the ParentID is also a UserID of its own and in the same table.
SELECT * FROM tbl where ParentID=2000 gives the below output
UserID Logon ParentID
2000 Test Team 2500
Again, the ParentID of this is also stored as a UserID..
SELECT * FROM tbl where ParentID=2500 gives the below output
UserID Logon ParentID
2500 Test Division NULL
I want a query that will pull all of these relationships and the logons into one row, with my output looking like the below.
UserID Username Parent1 Parent2 Parent3 Parent4
2344 Test1 Test Team Test Division NULL NULL
2345 Test2 Test Team Test Division NULL NULL
The maximum number of parents a user can have is 4, in this case there is only 2. Can someone help me with the query needed to build this?
Appreciate any help
Thanks
Jess
You can use basicly LEFT JOIN. If you have static 4 parent it should work. If you have unknown parents you should do dynamic query.
SELECT U1.UserId
,U1.UserName
,U2.UserName AS Parent1
,U3.UserName AS Parent2
,U4.UserName AS Parent3
,U5.UserName AS Parent4
FROM Users U1
LEFT JOIN Users U2 ON U1.ParentId = U2.UserId
LEFT JOIN Users U3 ON U2.ParentId = U3.UserId
LEFT JOIN Users U4 ON U3.ParentId = U4.UserId
LEFT JOIN Users U5 ON U4.ParentId = U5.UserId
EDIT : Additional(to exclude parent users from the list) :
WHERE NOT EXISTS (SELECT 1 FROM Users UC WHERE U1.UserId = UC.ParentId)
select
tb1.UserId as UserId,
tb1.UserName as UserName,
tb2.UserName as Parent1,
tb3.UserName as Parent2,
tb4.UserName as Parent3,
tb5.UserName as Parent4
from tbl t1
left join tbl t2 on t2.UserId=t1.ParentID
left join tbl t3 on t3.UserId=t2.ParentID
left join tbl t4 on t4.UserId=t3.ParentID
left join tbl t5 on t5.UserId=t4.ParentID;
you need to do 4 left joins in order to fetch 4 parent details
Use a recursive CTE to get the levels then pivot to put them in columns:
WITH cte(UserID, Logon, ParentID, ParentLogon, ParentLevel) AS
(
SELECT UserID, Logon, ParentID, Logon, 0
FROM users
UNION ALL
SELECT u.UserID, u.Logon, u.ParentID, cte.ParentLogon, ParentLevel + 1
FROM users u
JOIN cte ON cte.UserID = u.ParentID
)
SELECT UserId, Logon, Parent1, Parent2, Parent3, Parent4 FROM cte
PIVOT (
MAX(ParentLogon)
FOR ParentLevel
IN (
1 AS Parent1,
2 AS Parent2,
3 AS Parent3,
4 AS Parent4
)
)
See SQL Fiddle example
In order to get all parent or child, it's efficient to use a recursive function which would fetch the whole hierarchy.
Sample Table:
CREATE TABLE #TEST
(
[Name] varchar(100),
ManagerName Varchar(100),
Number int
)
Insert some values
Insert into Test values
('a','b'), ('b','c'), ('c','d'), ('d','e'), ('e','f'), ('f','g')
Create recursive function as below
CREATE FUNCTION [dbo].[fnRecursive] (#EmpName Varchar(100), #incremental int)
RETURNS #ret TABLE
(
ManagerName varchar(100),
Number int
)
AS
BEGIN
Declare #MgrName varchar(100)
SET #MgrName = (Select ManagerName from test where [name] = #EmpName)
Insert into #ret values (#MgrName, #incremental)
if(#MgrName is not null)
BEGIN
SET #incremental = #incremental + 1;
Insert into #ret
Select ManagerName, Number from [fnRecursive](#MgrName, #incremental)
END
RETURN;
END
If this function is joined with table, it should list the hierarchy for all employees
CREATE TABLE #TEST
(
[Name] varchar(100),
ManagerName Varchar(100),
Number int
)
Insert into #TEST
Select x.[Name], x.ManagerName,x.number from (
select t.[Name],a.ManagerName as managerName, a.number as number from TEST t outer apply
(
select * from [fnRecursive](t.[Name],1)
) a)
x
Select * from #Test
If we do a pivot on the table (excluding the 'Number' column). Assuming we store in the table "#temp" it should list all the managers as a column.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.[ManagerName] )
FROM #temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'select * from #temp
pivot
(
min([managername])
for managername in (' + #cols + ')
) p '
execute(#query)
But this doesn't name the column as 'Parent1', 'Parent2' instead with the dynamic column name.
Link below should help to set custom column name for the dynamic pivot table
https://stackoverflow.com/questions/16614994/sql-server-pivot-with-custom-column-names
Related
This question already has answers here:
How to use GROUP BY to concatenate strings in SQL Server?
(22 answers)
Closed 4 years ago.
DECLARE #Count BIGINT
SELECT #Count = Count(ID)
FROM Users;
SELECT TOP 50
CustUser.[ID],
CustUser.[FirstName] + ' ' + CustUser.[LastName] FirstName,
CustUser.[NickName],
CustUser.[UserName],
R.[Name] Roles
FROM
(SELECT
ROW_NUMBER() OVER(ORDER BY US.ID Desc) AS Row,
US.[ID], US.[FirstName], US.[LastName], US.[NickName],
US.[UserName], US.[Password]
FROM
[Users] US) CustUser
LEFT JOIN
Category CL ON CustUser.[LoginModeCode] = CL.CategoryCode
LEFT JOIN
Category CS ON CustUser.[StatusCode] = CS.CategoryCode
LEFT JOIN
UserRoles UR ON UR.UserID = CustUser.ID
LEFT JOIN
Roles R ON R.ID = UR.RoleID
WHERE
CustUser.ID = 3 AND
[Row] > (1 - 1) * 50
ORDER BY
FirstName
This query returns the below output
ID FirstName NickName UserName Roles
----------------------------------------------------------------------------
3 ram jk ram Developer
3 ram jk ram TeamLeader
Roles only different in above rows. I am combining two rows.
But I want this output
ID FirstName NickName UserName Roles
--------------------------------------------------------------
3 ram jk ram Developer, TeamLeader
--Test Data
CREATE TABLE #Temp_table(
ID int,
FirstName nvarchar(200),
NickName nvarchar(200),
UserName nvarchar(200),
Roles nvarchar(200)
);
INSERT INTO #Temp_table VALUES (3,'ram','jk','ram','Developer');
INSERT INTO #Temp_table VALUES (3,'ram','jk','ram','TeamLeader');
INSERT INTO #Temp_table VALUES (3,'ram','jk','ram','XXXLeader');
--change temp_table to your select table
select ID,FirstName,NickName,UserName,
STUFF((
SELECT ', ' + Roles
FROM #Temp_table
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') Roles
from #Temp_table
group by ID,FirstName,NickName,UserName;
This is for SQL Server 2012. I need to generate a dataset containing links, and all links of links from a given starting ParentId given the following table
CREATE TABLE Relations (
Id INT NOT NULL PRIMARY KEY,
ParentId INT NOT NULL,
ChildId INT
);
So for the following dataset:
1 A B
2 B C
3 C D
4 F D
5 F G
6 X Y
7 Y Z
Starting with C, I'd expected to get back rows 1 to 5 as they're all linked to C through either parent or child hierarchies. E.g. G has parent F, which is parent of D, which is child of C.
It's not a standard hierarchy query as there's no real root, and I need to get links in both directions. So this means I can't use the CTE recursion trick.. here was my attempt:
--Hierarchical Query using Common Table Expressions
WITH ReportingTree (Id, Parent, Child, Lvl)
AS
(
--Anchor Member
SELECT Id,
ParentId,
ChildId,
0 as Lvl
FROM Relations WHERE ParentId = 9488
UNION ALL
--Recusive Member
SELECT
cl.Id,
cl.ParentId,
cl.ChildId,
r1.Lvl+1
FROM [dbo].[CompanyLinks] cl
INNER JOIN ReportingTree r1 ON ReportingTree.Parent = cl.Child
INNER JOIN ReportingTree r2 ON cl.FromCompanyId = r2.Parent <-- errors
)
SELECT * FROM ReportingTree
My second attempt involved a temp table and while loop. This works but turns out to be very slow:
BEGIN
CREATE TABLE #R (
Id INT NOT NULL PRIMARY KEY NONCLUSTERED,
ParentId INT NOT NULL,
ChildId INT
);
CREATE CLUSTERED INDEX IX_Parent ON #R (ParentId);
CREATE INDEX IX_Child ON #R (ChildId);
INSERT INTO #R
SELECT Id,ParentId ChildId
FROM Relations
WHERE ParentId = 9488 OR ChildId = 9488;
WHILE ##RowCount > 0
BEGIN
INSERT INTO #R
SELECT cl.Id,cl.ParentId, cl.ChildId
FROM #R INNER JOIN
Relations AS cl ON cl.ChildId = #R.ChildId OR cl.ParentId = #R.ParentId OR cl.ChildId = #R.Parent OR cl.ParentId = #R.Child
EXCEPT
SELECT Id,ParentId, ChildId
FROM #R;
END
SELECT * FROM Relations cl inner Join #Relations r ON cl.Id = #R.Id
DROP TABLE #R
END
Can anyone suggest a workable solution for this?
We match every row with every other row based on every combination of parent and child ids, and save the path along the way. Recursively we do this matching and make the path, in order to avoid infinite loops we check the path is not traversed previously, finally we have all nodes that has a path to the desired node(#Id):
WITH cte AS (
SELECT CompanyLinks.*, cast('(' + cast(ParentId as nvarchar(max)) + ','
+ cast(ChildId as nvarchar(max))+')' as nvarchar(max)) Path
FROM CompanyLinks
WHERE ParentId = #Id OR ChildId = #Id
UNION ALL
SELECT a.*,
cast(
c.Path + '(' +
cast(a.ParentId as nvarchar(max)) + ',' +
cast(a.ChildId as nvarchar(max)) + ')'
as nvarchar(max)
) Path
FROM CompanyLinks a JOIN cte c ON
a.ParentId = c.ChildId
OR c.ParentId = a.ChildId
OR c.ParentId = a.ParentId
OR c.ChildId = a.ChildId
where c.Path not like cast(
'%(' +
cast(a.ParentId as nvarchar(max)) + ',' +
cast(a.ChildId as nvarchar(max)) +
')%'
as nvarchar(max)
)
)
SELECT DISTINCT a.id, Company.Name, path from (
SELECT distinct ParentId as id, path FROM cte
union all
SELECT distinct ChildId as id, path FROM cte
) a inner join Company on Company.Id = a.Id
Here is a fiddle for it.
If you want distinct nodes just use:
SELECT DISTINCT id from (
SELECT distinct ParentId as id FROM cte
union all
SELECT distinct ChildId as id FROM cte
) a
at the end of query.
This query is actually a Breadth First Search on an un-directed graph.
Note: Based on Hogan comment, there is no need for checking the path, as there is a primary key in the relation table(which I did not noticed) we can look for the primary key in prior recursions to avoid infinite loops.
I have a database with a table called Items, that contains these columns:
ID - primary key, uniqueidentifier
Name - nvarchar(256)
ParentID - uniqueidentifier
The name field can be used to build out a path to the item, by iterating through each ParentId until it equals '11111111-1111-1111-1111-111111111111', which is a root item.
So if you had a table that had rows like
ID Name ParentID
-------------------------------------------------------------------------------------
11111111-1111-1111-1111-111111111112 grandparent 11111111-1111-1111-1111-111111111111
22222222-2222-2222-2222-222222222222 parent 11111111-1111-1111-1111-111111111112
33333333-3333-3333-3333-333333333333 widget 22222222-2222-2222-2222-222222222222
So if I looked up an item with id '33333333-3333-3333-3333-333333333333' in the example above, i'd want the path
/grandparent/parent/widget
returned. i've attempted to write a CTE, as it looks like that's how you'd normally accomplish something like this - but as I don't do very much SQL, I can't quite figure out where i'm going wrong. I've looked at some examples, and this is as close as I seem to be able to get - which only returns the child row.
declare #id uniqueidentifier
set #id = '10071886-A354-4BE6-B55C-E5DBCF633FE6'
;with ItemPath as (
select a.[Id], a.[Name], a.ParentID
from Items a
where Id = #id
union all
select parent.[Id], parent.[Name], parent.ParentID
from Items parent
inner join ItemPath as a
on a.Id = parent.id
where parent.ParentId = a.[Id]
)
select * from ItemPath
I have no idea how i'd declare a local variable for the path and keep appending to it in the recursive query. i was going to try to at least get all the rows to the parent before going after that. if anyone could help with that as well - i'd appreciate it.
well here's working solution
SQL FIDDLE EXAMPLE
declare #id uniqueidentifier
set #id = '33333333-3333-3333-3333-333333333333'
;with ItemPath as
(
select a.[Id], a.[Name], a.ParentID
from Items a
where Id = #id
union all
select parent.[Id], parent.[Name] + '/' + a.[Name], parent.ParentID
from ItemPath as a
inner join Items as parent on parent.id = a.parentID
)
select *
from ItemPath
where ID = '11111111-1111-1111-1111-111111111112'
I don't like it much, I think better solution will be to do it other way around. Wait a minute and I try to write another query :)
UPDATE here it is
SQL FIDDLE EXAMPLE
create view vw_Names
as
with ItemPath as
(
select a.[Id], cast(a.[Name] as nvarchar(max)) as Name, a.ParentID
from Items a
where Id = '11111111-1111-1111-1111-111111111112'
union all
select a.[Id], parent.[Name] + '/' + a.[Name], a.ParentID
from Items as a
inner join ItemPath as parent on parent.id = a.parentID
)
select *
from ItemPath
and now you can use this view
declare #id uniqueidentifier
set #id = '33333333-3333-3333-3333-333333333333'
select *
from vw_Names where Id = #id
I needed a slightly different version of this answer as I wanted to produce a list of all lineages in the tree. I also wanted to know the depth of each node. I added a temporary table of top level parents that I could loop through and a temporary table to build the result set.
use Items
Select *
Into #Temp
From Items
where ParentID=0
Declare #Id int
create table #Results
(
Id int,
Name nvarchar(max),
ParentId int,
Depth int
)
While (Select Count(*) From #Temp) > 0
Begin
Select Top 1 #Id = Id From #Temp
begin
with ItemPath as
(
select a.[Id], cast(a.[Name] as nvarchar(max))as Name, a.ParentID ,1 as
Depth
from Items a
where a.ID = #id
union all
select a.[Id], parent.[Name] + '/' + a.[Name], a.ParentID, 1 + Depth
from Items as a
inner join ItemPath as parent on parent.id = a.parentID
)
insert into #Results
select *
from ItemPath
end
Delete #Temp Where Id = #Id
End
drop table #Temp
select * from #Results
drop table #Results
If we start from the following table...
Id Name ParentID
1 Fred 0
2 Mary 0
3 Baker 1
4 Candle 2
5 Stick 4
6 Maker 5
We would get this result table.
Id Name ParentID Depth
1 Fred 0 1
2 Mary 0 1
3 Fred/Baker 1 2
4 Mary/Candle 2 2
5 Mary/Candle/Stick 4 3
6 Mary/Candle/Stick/Maker 5 4
I have the following tables -
Resource
--------------------
Id, ProjectId, Hours, ApproverId
Project
--------------------
Id, Name
The input is ApproverId. I need to retrieve all the rows that have matching ApproverId (simple enough). And for every resource that I get back, I also need to get their hours (same table) whose approverId is not the one that is passed in (business requirement, to be grayed out in the UI). What I'm doing right now is - get all resources based on ApproverId, stored them in a temp table, then do a distinct on Resource.Id, store it in a different temp table, and then for every Resource.Id, get the rows where the ApproverId is not the one that is passed. Can I combine it all in a single query instead of using temp tables?
Thanks!
Edit: I'm using SQL Server 2008 R2.
Edit 2: Here's my stored procedure. I have changed the logic slightly after reading the comments. Can we get rid of all temp tables and make it faster -
ALTER PROCEDURE GetResourceDataByApprover
#ApproverId UNIQUEIDENTIFIER
AS
CREATE TABLE #Table1
(
Id SMALLINT PRIMARY KEY
IDENTITY(1, 1) ,
ResourceId UNIQUEIDENTIFIER
)
CREATE TABLE #Table2
(
ResourceId UNIQUEIDENTIFIER ,
ProjectId UNIQUEIDENTIFIER ,
ProjectName NVARCHAR(1024)
)
INSERT INTO #Table1
SELECT DISTINCT
ResourceId
FROM dbo.Resource T
WHERE T.ApproverId = #ApproverId
DECLARE #i INT
DECLARE #numrows INT
DECLARE #resourceId UNIQUEIDENTIFIER
SET #i = 1
SET #numrows = ( SELECT COUNT(*)
FROM #Table1
)
IF #numrows > 0
WHILE ( #i <= ( SELECT MAX(Id)
FROM #Table1
) )
BEGIN
SET #resourceId = ( SELECT ResourceId
FROM #Table1
WHERE Id = #i
)
INSERT INTO #Table2
SELECT
T.ResourceId ,
T.ProjectId ,
P.Name AS ProjectName
FROM dbo.[Resource] T
INNER JOIN dbo.Project P ON T.ProjectId = P.ProjectId
WHERE T.ResourceId = #resourceId
SET #i = #i + 1
END
SELECT *
FROM #Table1
SELECT *
FROM #Table2
DROP TABLE #Table1
DROP TABLE #Table2
This query should return two rows for every resource, one for the specified approver and one for all other approvers.
SELECT
Id,
CASE
WHEN ApproverId=#approverId THEN 'SpecifiedApprover'
ELSE 'OtherApprover'
END AS Approver,
SUM(Hours) AS Hours
FROM Resource
GROUP BY
Id,
CASE
WHEN ApproverId=#approverId THEN 'SpecifiedApprover'
ELSE 'OtherApprover'
END
Do you want to know how concrete Approver wastes his time?
SELECT p.Id, p.Name, SUM(r.Hours) as TotalHours
FROM Resource r
LEFT JOIN Project p
ON r.ProjectId = p.Id
WHERE ApproverId = %ConcreteApproverId%
GROUP BY p.Id, p.Name
HAVING SUM(r.Hours) > 0
This query will produce this table example:
+-----+----------+-------+
| Id | Project | Hours |
+-----+----------+-------+
| 203 | ProjectA | 25 |
| 202 | ProjectB | 34 |
| 200 | ProjectC | 46 |
+-----+----------+-------+
What is the simplest way of doing a recursive self-join in SQL Server? I have a table like this:
PersonID | Initials | ParentID
1 CJ NULL
2 EB 1
3 MB 1
4 SW 2
5 YT NULL
6 IS 5
And I want to be able to get the records only related to a hierarchy starting with a specific person. So If I requested CJ's hierarchy by PersonID=1 I would get:
PersonID | Initials | ParentID
1 CJ NULL
2 EB 1
3 MB 1
4 SW 2
And for EB's I'd get:
PersonID | Initials | ParentID
2 EB 1
4 SW 2
I'm a bit stuck on this can can't think how to do it apart from a fixed-depth response based on a bunch of joins. This would do as it happens because we won't have many levels but I would like to do it properly.
Thanks! Chris.
WITH q AS
(
SELECT *
FROM mytable
WHERE ParentID IS NULL -- this condition defines the ultimate ancestors in your chain, change it as appropriate
UNION ALL
SELECT m.*
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
By adding the ordering condition, you can preserve the tree order:
WITH q AS
(
SELECT m.*, CAST(ROW_NUMBER() OVER (ORDER BY m.PersonId) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN AS bc
FROM mytable m
WHERE ParentID IS NULL
UNION ALL
SELECT m.*, q.bc + '.' + CAST(ROW_NUMBER() OVER (PARTITION BY m.ParentID ORDER BY m.PersonID) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
ORDER BY
bc
By changing the ORDER BY condition you can change the ordering of the siblings.
Using CTEs you can do it this way
DECLARE #Table TABLE(
PersonID INT,
Initials VARCHAR(20),
ParentID INT
)
INSERT INTO #Table SELECT 1,'CJ',NULL
INSERT INTO #Table SELECT 2,'EB',1
INSERT INTO #Table SELECT 3,'MB',1
INSERT INTO #Table SELECT 4,'SW',2
INSERT INTO #Table SELECT 5,'YT',NULL
INSERT INTO #Table SELECT 6,'IS',5
DECLARE #PersonID INT
SELECT #PersonID = 1
;WITH Selects AS (
SELECT *
FROM #Table
WHERE PersonID = #PersonID
UNION ALL
SELECT t.*
FROM #Table t INNER JOIN
Selects s ON t.ParentID = s.PersonID
)
SELECT *
FROm Selects
The Quassnoi query with a change for large table. Parents with more childs then 10: Formating as str(5) the row_number()
WITH q AS
(
SELECT m.*, CAST(str(ROW_NUMBER() OVER (ORDER BY m.ordernum),5) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN AS bc
FROM #t m
WHERE ParentID =0
UNION ALL
SELECT m.*, q.bc + '.' + str(ROW_NUMBER() OVER (PARTITION BY m.ParentID ORDER BY m.ordernum),5) COLLATE Latin1_General_BIN
FROM #t m
JOIN q
ON m.parentID = q.DBID
)
SELECT *
FROM q
ORDER BY
bc
SQL 2005 or later, CTEs are the standard way to go as per the examples shown.
SQL 2000, you can do it using UDFs -
CREATE FUNCTION udfPersonAndChildren
(
#PersonID int
)
RETURNS #t TABLE (personid int, initials nchar(10), parentid int null)
AS
begin
insert into #t
select * from people p
where personID=#PersonID
while ##rowcount > 0
begin
insert into #t
select p.*
from people p
inner join #t o on p.parentid=o.personid
left join #t o2 on p.personid=o2.personid
where o2.personid is null
end
return
end
(which will work in 2005, it's just not the standard way of doing it. That said, if you find that the easier way to work, run with it)
If you really need to do this in SQL7, you can do roughly the above in a sproc but couldn't select from it - SQL7 doesn't support UDFs.
Check following to help the understand the concept of CTE recursion
DECLARE
#startDate DATETIME,
#endDate DATETIME
SET #startDate = '11/10/2011'
SET #endDate = '03/25/2012'
; WITH CTE AS (
SELECT
YEAR(#startDate) AS 'yr',
MONTH(#startDate) AS 'mm',
DATENAME(mm, #startDate) AS 'mon',
DATEPART(d,#startDate) AS 'dd',
#startDate 'new_date'
UNION ALL
SELECT
YEAR(new_date) AS 'yr',
MONTH(new_date) AS 'mm',
DATENAME(mm, new_date) AS 'mon',
DATEPART(d,#startDate) AS 'dd',
DATEADD(d,1,new_date) 'new_date'
FROM CTE
WHERE new_date < #endDate
)
SELECT yr AS 'Year', mon AS 'Month', count(dd) AS 'Days'
FROM CTE
GROUP BY mon, yr, mm
ORDER BY yr, mm
OPTION (MAXRECURSION 1000)
DELIMITER $$
DROP PROCEDURE IF EXISTS `myprocDURENAME`$$
CREATE DEFINER=`root`#`%` PROCEDURE `myprocDURENAME`( IN grp_id VARCHAR(300))
BEGIN
SELECT h.ID AS state_id,UPPER(CONCAT( `ACCNAME`,' [',b.`GRPNAME`,']')) AS state_name,h.ISACTIVE FROM accgroup b JOIN (SELECT get_group_chield (grp_id) a) s ON FIND_IN_SET(b.ID,s.a) LEFT OUTER JOIN acc_head h ON b.ID=h.GRPID WHERE h.ID IS NOT NULL AND H.ISACTIVE=1;
END$$
DELIMITER ;
////////////////////////
DELIMITER $$
DROP FUNCTION IF EXISTS `get_group_chield`$$
CREATE DEFINER=`root`#`%` FUNCTION `get_group_chield`(get_id VARCHAR(999)) RETURNS VARCHAR(9999) CHARSET utf8
BEGIN
DECLARE idd VARCHAR(300);
DECLARE get_val VARCHAR(300);
DECLARE get_count INT;
SET idd=get_id;
SELECT GROUP_CONCAT(id)AS t,COUNT(*) t1 INTO get_val,get_count FROM accgroup ag JOIN (SELECT idd AS n1) d ON FIND_IN_SET(ag.PRNTID,d.n1);
SELECT COUNT(*) INTO get_count FROM accgroup WHERE PRNTID IN (idd);
WHILE get_count >0 DO
SET idd=CONCAT(idd,',', get_val);
SELECT GROUP_CONCAT(CONCAT('', id ,'' ))AS t,COUNT(*) t1 INTO get_val,get_count FROM accgroup ag JOIN (SELECT get_val AS n1) d ON FIND_IN_SET(ag.PRNTID,d.n1);
END WHILE;
RETURN idd;
-- SELECT id FROM acc_head WHERE GRPID IN (idd);
END$$
DELIMITER ;