is this possible, i have results like below and want to stuff or combine each id
Num id RMA
item1 1 0
item1 1 0
item1 1 0
item1 8 1
item1 8 1
item1 8 1
item1 1 0
item1 1 0
item1 1 0
item2 8 1
item2 8 1
item2 8 1
item2 8 1
item2 8 1
item2 8 1
item2 8 1
item2 1 0
i would like to get the results like below
item1 id1=3,id8=3,id1=3
item2 id8=7,id1=1
If it's SQL server:
You can use a GROUP BY clause:
SELECT Num
,id
,COUNT(RMA) AS Count_RMA
FROM Table
GROUP BY Num
,id
It will output a table that counts each RMA for each unique Num and id combinaison.
Like this:
Num id Count_RMA
item1 1 6
item1 8 3
item2 8 7
item2 1 1
It is not difficult, however, you will need to create some additional steps, see the code bellow:
DECLARE #items TABLE (Num varchar(10) , id INT, RMA int , _group int default(0) )
declare #gIndcator int = 0 , #old_id int = 0
insert #items (num,id,rma) select 'item1' , 1 , 0
insert #items (num,id,rma) select 'item1' , 1 , 0
insert #items (num,id,rma) select 'item1' , 1 , 0
insert #items (num,id,rma) select 'item1' , 8 , 1
insert #items (num,id,rma) select 'item1' , 8 , 1
insert #items (num,id,rma) select 'item1' , 8 , 1
insert #items (num,id,rma) select 'item1' , 1 , 0
insert #items (num,id,rma) select 'item1' , 1 , 0
insert #items (num,id,rma) select 'item1' , 1 , 0
insert #items (num,id,rma) select 'item2' , 8 , 1
insert #items (num,id,rma) select 'item2' , 8 , 1
insert #items (num,id,rma) select 'item2' , 8 , 1
insert #items (num,id,rma) select 'item2' , 8 , 1
insert #items (num,id,rma) select 'item2' , 8 , 1
insert #items (num,id,rma) select 'item2' , 8 , 1
insert #items (num,id,rma) select 'item2' , 8 , 1
insert #items (num,id,rma) select 'item2' , 1 , 0
UPDATE #items
SET #gIndcator = _group = case when #old_id <> id then #gIndcator + 1 else #gIndcator end
, #old_id = id
select * from #items
select distinct
num
, ids = stuff((
select ',id'+convert(varchar(12),b.id) + '=' +convert(varchar(12),b._count)
from (
SELECT num, id , _group, COUNT(1) _count
FROM #items c
where a.Num = c.Num
group by Num, id,_group) b
where a.Num = b.Num
order by b.Num,_group
for xml path (''), type).value('.','nvarchar(max)')
,1,1,'')
from #items a
item1 id1=3,id8=3,id1=3
item2 id8=7,id1=1
It looks something like this:
select t.*,
stuff( (select ',' + cast(id as varchar(max)) + '=' + cast(cnt as varchar(max))
from t tt
where t.num = tt.num
group by id
for xml path ('')
), 1, 1, ''
) as
from (select num from t) t
;WITH CTE(Num , id, RMA)
AS
(
SELECT 'item1', 1 , 0 UNION ALL
SELECT 'item1', 1 , 0 UNION ALL
SELECT 'item1', 1 , 0 UNION ALL
SELECT 'item1', 8 , 1 UNION ALL
SELECT 'item1', 8 , 1 UNION ALL
SELECT 'item1', 8 , 1 UNION ALL
SELECT 'item1', 1 , 0 UNION ALL
SELECT 'item1', 1 , 0 UNION ALL
SELECT 'item1', 1 , 0 UNION ALL
SELECT 'item2', 8 , 1 UNION ALL
SELECT 'item2', 8 , 1 UNION ALL
SELECT 'item2', 8 , 1 UNION ALL
SELECT 'item2', 8 , 1 UNION ALL
SELECT 'item2', 8 , 1 UNION ALL
SELECT 'item2', 8 , 1 UNION ALL
SELECT 'item2', 8 , 1 UNION ALL
SELECT 'item2', 1 , 0
)
,Final
AS
(
SELECT Num,idval,cnt AS COUNT_RMA From
(
SELECT NUM,' id'+CASt(id AS Varchar(2))AS idval,cnt, ROW_NUMBER()OVEr(Partition by NUm,Cnt order by Num)AS Seq
From
(
SELECT NUm,id,COUNT(Id)Over(Partition by Num ,id order by Num)Cnt from CTE
)Dt
)Fnl
where Fnl.Seq=1
)
SELECT DISTINCT num, STUFF((SELECT DISTINCT ', '+CAST(''+CAST(idval AS VARCHAR)+'='+CAST(COUNT_RMA AS VARCHAR) AS VARCHAR(100))
From Final I WHERE O.Num=I.Num foR XML PATH('')),1,1,'') As Requiredvalue
from Final O
Related
I am trying to build a deep recursive self-join query. Having the table like:
Id | ParentId
1 | NULL
2 | 1
3 | 1
4 | 2
5 | 3
6 | 8
7 | 9
For Id 1 my query should be fetching 1,2,3,4,5 since they are either the children of 1 or children of the children of 1. In the given example 6 and 7 should not be included in the query result.
I tried using CTE but I am getting tons of duplicates:
WITH CTE AS (
SELECT Id, ParentId
FROM dbo.Table
WHERE ParentId IS NULL
UNION ALL
SELECT t.Id, t.ParentId
FROM dbo.Table t
INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT * FROM CTE
Ideas?
You can try to use DISTINCT to filter duplicate rows.
;WITH CTE AS (
SELECT Id, ParentId
FROM T
WHERE ParentId IS NULL
UNION ALL
SELECT t.Id, t.ParentId
FROM T
INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT DISTINCT Id, ParentId
FROM CTE
Try the following query with CTE where you can set parentId by #parentID:
DECLARE #parentID INT = 1
;WITH cte AS
(
SELECT
t.ID
, t.ParentId
FROM #table t
),
cteParent AS
(
SELECT
t.ID
, t.ParentId
FROM #table t
WHERE t.ParentId IN (SELECT t1.ID FROM #table t1 WHERE T1.ParentId = #parentID)
)
SELECT
DISTINCT c1.ID
, c1.ParentId
FROM cte c1
INNER JOIN cte c2 ON c2.ParentId = c1.ID
UNION ALL
SELECT *
FROM cteParent
And the sample data:
DECLARE #table TABLE
(
ID INT
, ParentId INT
)
INSERT INTO #table
(
ID,
ParentId
)
VALUES
(1, NULL )
, (2, 1 )
, (3, 1 )
, (4, 2 )
, (5, 3 )
, (6, 8 )
, (7, 9 )
OUTPUT:
ID ParentId
1 NULL
2 1
3 1
4 2
5 3
I don't see duplicates.
Your code returns the following on the data you provided:
Id ParentId
1
2 1
3 1
5 3
4 2
which is what you want.
Here is a db<>fiddle.
Here is the code:
WITH t as (
SELECT *
FROM (VALUES (1, NULL), (2, 1), (3, 1), (4, 2), (5, 3), (6, 8), (7, 9)
) v(id, parentId)
),
CTE AS (
SELECT Id, ParentId
FROM t
WHERE ParentId IS NULL
UNION ALL
SELECT t.Id, t.ParentId
FROM t
INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT *
FROM CTE;
If you are getting duplicates in your actual result set, then you presumably have duplicates in your original table. I would recommend removing them before doing the recursive logic:
with t as (
select distinct id, parentid
from <your query>
),
. . .
Then run the recursive logic.
Try this sql script which result Parent Child Hierarchy
;WITH CTE(Id , ParentId)
AS
(
SELECT 1 , NULL UNION ALL
SELECT 2 , 1 UNION ALL
SELECT 3 , 1 UNION ALL
SELECT 4 , 2 UNION ALL
SELECT 5 , 3 UNION ALL
SELECT 6 , 8 UNION ALL
SELECT 7 , 9
)
,Cte2
AS
(
SELECT Id ,
ParentId ,
CAST('\'+ CAST(Id AS VARCHAR(MAX))AS VARCHAR(MAX)) AS [Hierarchy]
FROM CTE
WHERE ParentId IS NULL
UNION ALL
SELECT c1.Id ,
c1.ParentId ,
[Hierarchy]+'\'+ CAST(c1.Id AS VARCHAR(MAX)) AS [Hierarchy]
FROM Cte2 c2
INNER JOIN CTE c1
ON c1.ParentId = c2.Id
)
SELECT Id,
RIGHT([Hierarchy],LEN([Hierarchy])-1) AS ParentChildHierarchy
FROM Cte2
GO
Result
Id ParentChildHierarchy
-------------------------
1 1
2 1\2
3 1\3
5 1\3\5
4 1\2\4
This query will help you
CREATE TABLE #table( ID INT, ParentId INT )
INSERT INTO #table(ID,ParentId)
VALUES (1, NULL ), (2, 1 ), (3, 1 ), (4, 2 ), (5, 3 ), (6, 8 ), (7, 9 )
;WITH CTE AS (
SELECT ID FROM #table WHERE PARENTID IS NULL
UNION ALL
SELECT T.ID FROM #table T
INNER JOIN #table T1 ON T.PARENTID =T1.ID
) SELECT * FROM CTE
I have data as below, data is order by date.
I need to copy the last non zero value when there is zero. For example 15th August the count is Zero so the count should show 20 as the last count is 20 (on 15th August), same should happen for 16th - 19 August. Now for 21st - 22nd the count should be 14. If no previous value is available let it be zero in case of 14th Aug.
I have also added the result at last.
Date Count
14-Aug-15 0
15-Aug-15 20
16-Aug-15 0
17-Aug-15 0
18-Aug-15 0
19-Aug-15 0
20-Aug-15 14
21-Aug-15 0
22-Aug-15 0
23-Aug-15 10
24-Aug-15 0
25-Aug-15 0
26-Aug-15 0
27-Aug-15 0
28-Aug-15 11
29-Aug-15 0
30-Aug-15 0
31-Aug-15 0
01-Sep-15 0
02-Sep-15 0
03-Sep-15 0
04-Sep-15 0
Result
Date Count
14-Aug-15 0
15-Aug-15 20
16-Aug-15 20
17-Aug-15 20
18-Aug-15 20
19-Aug-15 20
20-Aug-15 14
21-Aug-15 14
22-Aug-15 14
23-Aug-15 10
24-Aug-15 10
25-Aug-15 10
26-Aug-15 10
27-Aug-15 10
28-Aug-15 11
29-Aug-15 11
30-Aug-15 11
31-Aug-15 11
01-Sep-15 11
02-Sep-15 11
03-Sep-15 11
04-Sep-15 11
A simple subquery can get you your result set as desired (with the last current or previous non-zero value).
select [Date],
isnull((select top 1 [Previous].[Count]
from [Table] as [Previous]
where [Previous].[Count] <> 0 and
[Previous].[Date] <= [Table].[Date] and
[Previous].[Id] = [Table].[Id]
order by [Previous].[Date] desc),
0) as [Count]
from [Table]
To update values is very similar :
update [Table] set [Count]= isnull((select top 1 [Previous].[Count]
from [Table] as [Previous]
where [Previous].[Count] <> 0 and
[Previous].[Date] <= [Table].[Date] and
[Previous].[Id] = [Table].[Id]
order by [Previous].[Date] desc),
0) as [Count]
You may use a variable to achieve it
CREATE TABLE tab
(
n VARCHAR(10),
d DATE,
c INT
);
INSERT INTO tab VALUES ('A', '14-Aug-15', 0);
INSERT INTO tab VALUES ('B', '15-Aug-15', 20);
INSERT INTO tab VALUES ('C', '16-Aug-15', 0);
INSERT INTO tab VALUES ('A', '17-Aug-15', 0);
INSERT INTO tab VALUES ('B', '18-Aug-15', 0);
INSERT INTO tab VALUES ('C', '19-Aug-15', 0);
INSERT INTO tab VALUES ('D', '20-Aug-15', 14);
INSERT INTO tab VALUES ('A', '21-Aug-15', 0);
-- for each n value perform the following update
DECLARE #last INT=0;
UPDATE tab
SET #last=c=CASE WHEN c=0 THEN #last ELSE c END
WHERE n = 'B';
I think below code should work for you -
Create table #Source (
id char(1) ,
date smalldatetime,
value tinyint)
go
insert into #Source
select 'A' ,'14-Aug-15' , 0
union all select 'B' , '15-Aug-15' , 20
union all select 'B' , '16-Aug-15' , 0
union all select 'B' , '17-Aug-15' , 0
union all select 'B' , '18-Aug-15' , 0
union all select 'A' , '19-Aug-15' , 0
union all select 'A' , '20-Aug-15' , 14
union all select 'A' , '21-Aug-15' , 0
union all select 'B' , '22-Aug-15' , 0
union all select 'B', '23-Aug-15' , 10
union all select 'B' , '24-Aug-15' , 0
union all select 'B' , '25-Aug-15' , 0
union all select 'B' , '26-Aug-15' , 0
union all select 'C' , '27-Aug-15' , 0
union all select 'C' , '28-Aug-15' , 11
union all select 'C' , '29-Aug-15' , 0
union all select 'C' , '30-Aug-15' , 0
union all select 'C' , '31-Aug-15' , 0
union all select 'C' , '01-Sep-15' , 0
union all select 'B' , '02-Sep-15' , 0
union all select 'B' , '03-Sep-15' , 0
union all select 'A' , '04-Sep-15' , 0
select t1.* , t2.value New_value , RANK() over ( partition by t1.date
order by t2.date desc ) as RANK
into #dest
from #Source t1
left join #Source t2 on t1.id = t2.id and t1.date >= t2.date
and t1.value=0 and t2.value <>0
order by 2
update s
set s.Value = d.New_value
from #Source s join #dest d
on s.id = d.id
and s.date = d.date
and d.RANK = 1 and d.New_value is not null
I have the following data in my table
ID NAME PARENTID STATUS
----------- ------------------------------ ----------- ------
1 Folder A 0 0
2 Folder B 1 0
3 Folder C 2 1
4 Folder D 1 0
5 Folder E 4 0
6 Folder G 5 0
7 Folder H 6 1
Above records are from table [#Temp].
[Name] - Folder Name
[ID] - Unique ID of folder in database (identity)
[ParentID] - Represents the parent of current folder.
Query to populate above data in the table:
DECLARE #Temp TABLE
(
[ID] INT IDENTITY(1, 1) ,
[NAME] VARCHAR(30) ,
[PARENTID] INT,
[STATUS] BIT
)
INSERT INTO #Temp
SELECT 'Folder A' ,
0, 0
UNION
SELECT 'Folder B' ,
1, 0
UNION
SELECT 'Folder C' ,
2, 1
UNION
SELECT 'Folder D' ,
1, 0
UNION
SELECT 'Folder E' ,
4, 0
UNION
SELECT 'Folder G' ,
5, 0
UNION
SELECT 'Folder H' ,
6, 1
I am having the following query to get records where status=1
SELECT *
FROM #Temp WHERE [STATUS]=1
which gives the following output
ID NAME PARENTID STATUS
----------- ------------------------------ ----------- ------
3 Folder C 2 1
7 Folder H 6 1
My goal is to fetch those records too which are the parents (till parentid=0) of the records came with the above query. i.e I want to get this output which contains the parents of Folder C and Folder H:
ID NAME PARENTID STATUS
----------- ------------------------------ ----------- ------
1 Folder A 0 0
2 Folder B 1 0
3 Folder C 2 1
4 Folder D 1 0
5 Folder E 4 0
6 Folder G 5 0
7 Folder H 6 1
DECLARE #Temp TABLE
(
[ID] INT IDENTITY(1, 1) ,
[NAME] VARCHAR(30) ,
[PARENTID] INT ,
[STATUS] BIT
)
INSERT INTO #Temp
SELECT 'Folder A' ,
0 ,
0
UNION
SELECT 'Folder B' ,
1 ,
0
UNION
SELECT 'Folder C' ,
2 ,
1
UNION
SELECT 'Folder D' ,
1 ,
0
UNION
SELECT 'Folder E' ,
4 ,
0
UNION
SELECT 'Folder G' ,
5 ,
1
UNION
SELECT 'Folder H' ,
6 ,
0
CREATE TABLE #TempTable
(
[RowIndex] INT IDENTITY(1, 1) ,
[ID] INT ,
[ParentID] INT
)
DECLARE #TempIds TABLE ( [ID] INT )
INSERT INTO #TempTable
( [ID] ,
[ParentID]
)
SELECT [ID] ,
[ParentID]
FROM #Temp
WHERE [STATUS] = 1
DECLARE #intFlag INT
DECLARE #Count INT
SET #intFlag = 1
SELECT #Count = COUNT(1)
FROM #Temp
WHILE ( #intFlag <= #Count )
BEGIN
PRINT #intFlag
DECLARE #ID INT
SELECT #ID = [ParentID]
FROM #TempTable
WHERE RowIndex = #intFlag
SET #intFlag = #intFlag + 1;
WITH CTE
AS ( SELECT ID ,
ParentID
FROM #Temp
WHERE ID = #ID
UNION ALL
SELECT MainTbl.ID ,
MainTbl.ParentID
FROM #Temp MainTbl
INNER JOIN cte ON MainTbl.ID = cte.ParentID
)
INSERT INTO #TempIds
SELECT ID
FROM CTE
END
;WITH cte
AS ( SELECT DISTINCT
ID
FROM #TempIds
)
SELECT T.*
FROM cte
INNER JOIN #Temp T ON [T].ID = cte.ID
UNION
SELECT T1.*
FROM #TempTable TempTable
INNER JOIN #Temp T1 ON [TempTable].ID = T1.ID
DROP TABLE #TempTable
Output:
ID NAME PARENTID STATUS
----------- ------------------------------ ----------- ------
1 Folder A 0 0
2 Folder B 1 0
3 Folder C 2 1
4 Folder D 1 0
5 Folder E 4 0
6 Folder G 5 1
I made a recursive CTE - I start with the bottom, any folder that does not have a child. From there, I pass up whether or not a '1' Status was encountered in the 'GOOD' column, and the distinct clears out the duplicates created by starting at the bottom.
;WITH CTE AS
(
SELECT ID, NAME, PARENTID, STATUS GOOD, STATUS
FROM #Temp T1
WHERE NOT EXISTS (SELECT * FROM #Temp T2 WHERE T2.PARENTID = T1.ID)
UNION ALL
SELECT T.ID, T.NAME, T.PARENTID, T.STATUS | C.GOOD GOOD, T.STATUS
FROM #Temp T
JOIN CTE C
ON C.PARENTID = T.ID
)
SELECT DISTINCT ID, NAME, PARENTID, STATUS FROM CTE
WHERE GOOD = 1
ORDER BY ID ASC
I have a table With data like below (Table 1)
id valueId Value
----------- ----------- --------------------------------------------------
1 1 Value 1
1 1 Value 2
1 1 Value 3
1 2 Value 1
1 2 Value 2
1 2 Value 3
And i have another dataset like below (DataSet)
id valueId Value
----------- ----------- -------
1 1 Value 1
1 1 Value 2
1 1 Value 4
now i need to insert records that are not exists in the Table 1 (You can see the record
id valueId Value
----------- ----------- -------
1 1 Value 4
is not in the Table 1, that record should insert) and need to delete records from Table 1 that are not in DataSet which is
id valueId Value
----------- ----------- -------
1 1 Value 3
, but without affecting other records (other records means records that id=1 and valueId=2).
I have used the following T-SQL that i have wrote it using MERGE, It inserts the missing records but it deletes all the records that are not in the DataSet
DECLARE #tmp_value AS TABLE
(
id INT ,
valueId INT ,
[Value] NVARCHAR(50)
) ;
INSERT #tmp_value
( [id], [valueId], [Value] )
VALUES ( 1, 1, N'Value 1' ),
( 1, 1, N'Value 2' ),
( 1, 1, N'Value 3' ),
( 1, 2, N'Value 1' ),
( 1, 2, N'Value 2' ),
( 1, 2, N'Value 3' ) ;
--SELECT *
--FROM #tmp_value AS TV ;
WITH cte
AS ( SELECT 1 AS id , 1 AS valueId , 'Value 1' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 2' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 4' AS [Value]
)
MERGE #tmp_value AS TV
USING cte
ON [cte].[id] = [TV].[id]
AND [cte].[valueId] = [TV].[valueId]
AND [cte].[Value] = [TV].[Value]
WHEN NOT MATCHED
THEN INSERT VALUES ( id , [valueId] , [Value] )
WHEN NOT MATCHED BY SOURCE
THEN DELETE ;
SELECT *
FROM #tmp_value
Expected Result:
id valueId Value
----------- ----------- --------------------------------------------------
1 1 Value 1
1 1 Value 2
1 1 Value 4
1 2 Value 1
1 2 Value 2
1 2 Value 3
Update :
DECLARE #tmp_value AS TABLE
(
id INT ,
valueId INT ,
[Value] NVARCHAR(50)
) ;
INSERT #tmp_value
( [id], [valueId], [Value] )
VALUES ( 1, 1, N'Value 1' ),
( 1, 1, N'Value 2' ),
( 1, 1, N'Value 3' ),
( 1, 2, N'Value 1' ),
( 1, 2, N'Value 2' ),
( 1, 2, N'Value 3' ) ;
--SELECT *
--FROM #tmp_value AS TV ;
WITH cte
AS ( SELECT 1 AS id , 1 AS valueId , 'Value 1' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 2' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 4' AS [Value]
)
MERGE #tmp_value AS TV
USING cte
ON [cte].[id] = [TV].[id]
AND [cte].[valueId] = [TV].[valueId]
AND [cte].[Value] = [TV].[Value]
WHEN NOT MATCHED
THEN INSERT VALUES ( id , [valueId] , [Value] )
;
WITH cte
AS ( SELECT 1 AS id , 1 AS valueId , 'Value 1' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 2' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 4' AS [Value]
)
MERGE #tmp_value AS TV
USING cte
ON ([cte].[id] = [TV].[id]
AND [cte].[valueId] = [TV].[valueId]
AND [cte].[Value] = [TV].[Value])
or not( [TV].[id] in (select distinct id from cte)
and [TV].[valueId] in (select distinct valueid from cte))
WHEN NOT MATCHED
THEN INSERT VALUES ( id , [valueId] , [Value] )
WHEN NOT MATCHED BY Source
THEN DELETE ;
SELECT *
FROM #tmp_value
I have a CTE-query that displays a tree using recursion. This works great when displaying the whole tree. But I want to pass in ID as a variable and include the siblings for each current node.
Testcode:
DECLARE #TT TABLE
(
ID int,
Name varchar(25),
ParentID int,
SortIndex int
)
INSERT #TT
SELECT 1, 'A', NULL, 1 UNION ALL
SELECT 2, 'B_1', 3, 1 UNION ALL
SELECT 3, 'B', 1, 2 UNION ALL
SELECT 4, 'B_2', 3, 2 UNION ALL
SELECT 5, 'C', 1, 3 UNION ALL
SELECT 6, 'C_2', 5, 2 UNION ALL
SELECT 7, 'A_1', 1, 1 UNION ALL
SELECT 8, 'A_2', 1, 2 UNION ALL
SELECT 9, 'C_1', 5, 1
;WITH CTETree
AS
(
SELECT *, CAST(NULL AS VARCHAR(25)) AS ParentName, 1 AS Lev,
CAST(ROW_NUMBER() OVER(ORDER BY SortIndex) AS VARBINARY(MAX)) AS SortPath
FROM #TT
WHERE ParentID IS NULL
UNION ALL
SELECT F.*, CTETree.Name AS ParentName, Lev + 1,
SortPath + CAST(ROW_NUMBER() OVER(ORDER BY F.SortIndex) AS BINARY(32))
FROM #TT AS F
INNER JOIN CTETree
ON F.ParentID = CTETree.ID
)
SELECT * FROM CTETree
ORDER BY SortPath
/*
DESIRED RESULT:
WHEN ID = 3 PASSED IN:
1 A NULL 1 NULL 1
3 B 1 2 A 2
2 B_1 3 1 B 3
4 B_2 3 2 B 3
5 C 1 3 A 2
WHEN ID = 1 PASSED IN:
1 A NULL 1 NULL 1
3 B 1 2 A 2
5 C 1 3 A 2
WHEN ID = 9 PASSED IN:
1 A NULL 1 NULL 1
3 B 1 2 A 2
5 C 1 3 A 2
9 C_1 5 1 C 3
6 C_2 5 2 C 3
*/
SQL-Fiddle: http://sqlfiddle.com/#!3/d41d8/5526
Only in once I confront a question where disappear A_1 and A_2. Therefore add in exception(in case clause).
If you need this records delete this expression AND f.ID != 7 AND f.ID != 8.
DECLARE #ID int = 3 -- variable wich you want pass
DECLARE #Matched int = (SELECT CASE WHEN ParentID = 1 THEN ID ELSE ParentID END FROM #TT WHERE ID = #ID)
;WITH CTETree
AS
(
SELECT *, CAST(NULL AS VARCHAR(25)) AS ParentName, 1 AS Lev,
CAST(ROW_NUMBER() OVER(ORDER BY SortIndex) AS VARBINARY(MAX)) AS SortPath,
0 AS Matched
FROM #TT
WHERE ParentID IS NULL
UNION ALL
SELECT F.*, cte.Name AS ParentName, cte.Lev + 1,
SortPath + CAST(ROW_NUMBER() OVER(ORDER BY F.SortIndex) AS BINARY(32)),
CASE WHEN (cte.ID = 1 AND f.ID != 7 AND f.ID != 8)
OR (cte.ID = #Matched AND cte.Lev + 1 > 2)
THEN 1 END AS Matched
FROM #TT AS F INNER JOIN CTETree cte
ON F.ParentID = cte.ID
)
SELECT ID, Name, ParentID, SortIndex, ParentName, Lev FROM CTETree
WHERE Matched IS NOT NULL
ORDER BY SortPath
Demo on SQLFiddle