Create hierarchical formatted output from table - sql-server-2008

I have a SQL table like this:
CC Descr C_NO Vol Wt
2050 Des1 123 20 40
2060 Des2 123 30 50
2050 Des1 125 20 40
2060 Des2 125 30 50
2050 Des1 126 20 40
and I want output like this:
2050
Des1
123
20
40
125
20
40
126
20
40
2060
Des2
123
30
50
125
30
50
How can I do that using TSQL code?
For every similar CC value which always have similar Descr value, it shows all the C_No, Vol and Wt values related to that particular CC value in the sequence written in the output section.

Try this
DECLARE #t TABLE
(
CC BIGINT,
Descr NVARCHAR(10),
C_NO INT,
Vol SMALLINT,
WT SMALLINT
)
INSERT INTO #t(CC,Descr,C_NO,Vol,WT)
VALUES (2050,'Des1',123,20,40)
,(2060,'Des2',123,30,50)
,(2050,'Des1',125,20,40)
,(2060,'Des2',125,30,50)
,(2050,'Des1',126,20,40)
;WITH CTE1 AS(
SELECT
t1.CC
,t1.Descr
,MergedColumn = STUFF(
(SELECT
','
+ CAST(C_NO AS VARCHAR(10)) + '/' + CAST(Vol AS VARCHAR(10)) + '/' + CAST(Wt AS VARCHAR(10))
FROM #t AS t2
WHERE t2.CC=t1.CC AND t2.Descr=t2.Descr
FOR XML PATH('')),1,1,'')
FROM #t t1
GROUP BY t1.CC,t1.Descr)
,CTE2 AS
(
SELECT
X.CC
,X.Descr
,Y.SplitDataByComma
FROM
(
SELECT
*,
CAST('<X>'+REPLACE(F.MergedColumn,',','</X><X>')+'</X>' AS XML) AS xmlfilter
FROM CTE1 F
)X
CROSS APPLY
(
SELECT fdata.D.value('.','varchar(50)') AS SplitDataByComma
FROM X.xmlfilter.nodes('X') AS fdata(D)
)Y
)
,CTE3 AS
(
SELECT
X.CC
,X.Descr
,Y.SplitDataBySlash
, X.SplitDataByComma AS GrpID
,ROW_NUMBER() OVER( PARTITION BY X.SplitDataByComma ORDER BY X.CC,X.Descr ) AS Rn
,X.SplitDataByComma + CAST(CC AS Varchar(200)) + CAST(Descr AS Varchar(200)) CC_Descr
FROM
(
SELECT
*,
CAST('<X>'+REPLACE(F.SplitDataByComma,'/','</X><X>')+'</X>' AS XML) AS xmlfilter
FROM CTE2 F
)X
CROSS APPLY
(
SELECT fdata.D.value('.','varchar(50)') AS SplitDataBySlash
FROM X.xmlfilter.nodes('X') AS fdata(D)
)Y
)
,CTE4 AS
(
SELECT
Rn = ROW_NUMBER() OVER(PARTITION BY CC ORDER BY CC)
,CC
,Descr
,CASE WHEN Rn = 1 THEN CAST (SplitDataBySlash AS VARCHAR(10)) ELSE ' ' END C_NO
,CASE WHEN Rn = 1 THEN ' ' ELSE CAST (SplitDataBySlash AS VARCHAR(10)) END Vol_Wt
,GrpID
FROM Cte3
)
,CTE5 AS(
SELECT
CC = CASE WHEN Rn > 1 THEN ' ' ELSE CAST(CC AS Varchar(200)) END
,Descr = CASE WHEN Rn > 1 THEN ' ' ELSE CAST(Descr AS Varchar(200)) END
,C_NO
,Vol_Wt
,GrpID
FROM Cte4)
SELECT
CHAR(10)
+ REPLICATE(SPACE(1),10)
+ CAST(CC as VARCHAR(100))
+ CHAR(10)
+ REPLICATE(SPACE(1),15)
+ Descr
+ CHAR(10)
+ REPLICATE(SPACE(1),10)
+ C_NO
+ CHAR(10)
+ REPLICATE(SPACE(1),15)
+ Vol_Wt
FROM CTE5
In Text Mode(CTRL + T), the result is
2050
Des1
123
20
40
125
20
40
126
20
40
2060
Des2
123
30
50
125
30
50
And in Grid Mode(CTRL + D) , the result is
(No column name)
2050
Des1
123
20
40
125
20
40
126
20
40
2060
Des2
123
30
50
125
30
50
However, SQL Server (or any database) is not the place to do formatting as others spoke about.Please look into the matter.

I wouldn't do this. TSQL is used to get the data, then you format that data with application code.
But if you're working in Query analyzer and just want the output there, you can try the following:
DECLARE mytable_cursor CURSOR FOR
SELECT CC, Descr, C_NO, Vol, Wt
FROM myTable
ORDER BY CC, Descr, C_NO
OPEN mytable_cursor;
FETCH NEXT FROM mytable_cursor
INTO #CC, #Descr, #C_NO, #Vol, #Wt
SET #oCC = #CC
SET #oDescr = #Descr
SET #oC_NO = #C_NO
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #CC;
WHILE ##FETCH_STATUS = 0 AND #oCC = #CC
BEGIN
PRINT ' ' + #Descr;
WHILE ##FETCH_STATUS = 0 AND #oDescr = #Descr
BEGIN
PRINT ' ' + #C_NO;
WHILE ##FETCH_STATUS = 0 AND #oC_NO = #C_NO
BEGIN
PRINT ' ' + #Vol;
PRINT ' ' + #WT;
FETCH NEXT FROM mytable_cursor
INTO #CC, #Descr, #C_NO, #Vol, #Wt
END
SET #oC_NO = #C_NO
END
SET #oDescr = #Descr
END
SET #oCC = #CC
END
CLOSE mytable_cursor;
DEALLOCATE mytable_cursor;
Or you can use a GROUP BY ... WITH ROLLUP and CASE WHEN to get the results a single query.
Here's an example with dashes instead of spaces to make sure the formatting is visible:
SELECT (CASE
WHEN Descr IS NULL THEN CC
WHEN C_NO IS NULL THEN '----' + Descr
WHEN Vol IS NULL THEN '--' + C_NO
WHEN Wt IS NULL THEN '------' + Vol
ELSE '------' + Wt
END)
FROM
(SELECT CC, Descr, C_NO, Vol, Wt
FROM my
GROUP BY CC, Descr, C_NO, Vol, Wt
WITH ROLLUP) AS x
WHERE CC IS NOT NULL
ORDER BY CC, Descr, C_NO, Vol, Wt

You can't do this in tsql code. You need to do this sort of thing in the application code.

One of the best way to represent data in hierarchical order is using XML. Something more, often the use of XML is connected with great performance.
Using your example information and this peace of code:
;WITH DistinctValues (CC,Descr ) AS
(
SELECT DISTINCT CC,Descr
FROM #TableOne
)
SELECT (
SELECT CC AS "CC/#CC"
,Descr AS "CC/Descr"
,(
SELECT C_NO AS "C_NO/#C_NO",
Vol AS "C_NO/Vol",
Wt AS "C_NO/Wt"
FROM #TableOne AS Data
WHERE Data.CC=DV.CC AND Data.Descr=DV.Descr
FOR XML PATH(''),TYPE
) AS "CC"
FROM DistinctValues AS DV
FOR XML PATH(''),TYPE
)
FOR XML PATH('Source'),TYPE
I get the following result (in the form of one row return by the statement above):
<Source>
<CC CC="2050">
<Descr>Des1</Descr>
<C_NO C_NO="123">
<Vol>20</Vol>
<Wt>40</Wt>
</C_NO>
<C_NO C_NO="125">
<Vol>20</Vol>
<Wt>40</Wt>
</C_NO>
<C_NO C_NO="126">
<Vol>20</Vol>
<Wt>40</Wt>
</C_NO>
</CC>
<CC CC="2060">
<Descr>Des2</Descr>
<C_NO C_NO="123">
<Vol>30</Vol>
<Wt>50</Wt>
</C_NO>
<C_NO C_NO="125">
<Vol>30</Vol>
<Wt>50</Wt>
</C_NO>
</CC>
</Source>
Note that the XML functions in T-SQL combined with the XML language structure gives you a huge of possible variations of output data formats - you use one or many nodes, you can represent the the data as attributes or node text. Combine this as you like and as you feel it will be easiest to work with in your application level.
Here is the whole code (just copy and paste) that I have used to generated the previous XML structure:
DECLARE #TableOne TABLE
(
CC BIGINT,
Descr NVARCHAR(10),
C_NO INT,
Vol SMALLINT,
WT SMALLINT
)
INSERT INTO #TableOne(CC,Descr,C_NO,Vol,WT)
VALUES (2050,'Des1',123,20,40)
,(2060,'Des2',123,30,50)
,(2050,'Des1',125,20,40)
,(2060,'Des2',125,30,50)
,(2050,'Des1',126,20,40)
;WITH DistinctValues (CC,Descr ) AS
(
SELECT DISTINCT CC,Descr
FROM #TableOne
)
SELECT (
SELECT CC AS "CC/#CC"
,Descr AS "CC/Descr"
,(
SELECT C_NO AS "C_NO/#C_NO",
Vol AS "C_NO/Vol",
Wt AS "C_NO/Wt"
FROM #TableOne AS Data
WHERE Data.CC=DV.CC AND Data.Descr=DV.Descr
FOR XML PATH(''),TYPE
) AS "CC"
FROM DistinctValues AS DV
FOR XML PATH(''),TYPE
)
FOR XML PATH('Source'),TYPE
This works like a charm and it is tested on Microsoft SQL Server Management Studio 2012.

Related

Required Sum result in separate columns as per different elements in SQL

I am new in SQL basically i required Sum result in separate columns as per different elements.
Please find my table and required result in below image.
Please guide me with regards to SQL query which give me the required result.
You can use conditional aggregation:
select payment,
sum(case when product = 'A' then amount else 0 end) as a,
sum(case when product = 'B' then amount else 0 end) as b,
sum(case when product = 'C' then amount else 0 end) as c,
sum(case when product = 'D' then amount else 0 end) as d,
sum(amount) as total
from t
group by payment;
You can use PIVOT to get the desired result
SELECT * ,
[A] + [B] + [C] + [D] AS Total
FROM ( SELECT Payment, Product, Amount FROM Your_Table) tr
PIVOT( SUM(Amount) FOR Product IN ( [A], [B], [C], [D] ) ) p;
You can use dynamic SQL pivot query if your products are not limited with A,B,C and D
Here is a sample query for SQL Server
DECLARE #products nvarchar(max)
SELECT #products =
STUFF(
(
select distinct ',[' + product + ']'
from Payments
for xml path('')
),
1,1,'')
declare #sql nvarchar(max)
set #sql = '
SELECT
*
FROM (
SELECT
Payment AS '' '',
Product,
Amount
from Payments
) Data
PIVOT (
SUM(Amount)
FOR Product
IN (
' + #products + '
)
) PivotTable'
exec sp_executesql #sql
Below is sample data
IF OBJECT_ID('tempdb..#t')IS NOT NULL
DROp TABLE #t
;with cte (Payment,Product,Amount)
AS
(
SELECT 'Cash','A',1 UNION ALL
SELECT 'Credit','B',2 UNION ALL
SELECT 'Credit','C',3 UNION ALL
SELECT 'Cash','D',5 UNION ALL
SELECT 'Cash','A',6 UNION ALL
SELECT 'Credit','B',23 UNION ALL
SELECT 'Credit','C',7 UNION ALL
SELECT 'Cash','D',11 UNION ALL
SELECT 'Cash','A',12 UNION ALL
SELECT 'Credit','B',14 UNION ALL
SELECT 'Credit','C',16 UNION ALL
SELECT 'Cash','D',26
)
SELECT * INTO #t FROM cte
Using Dynamic Sql
DECLARE #DyColumn Nvarchar(max),
#Sql Nvarchar(max),
#ISNULLDyColumn Nvarchar(max),
#SumCol Nvarchar(max)
SELECT #DyColumn=STUFF((SELECT DISTINCT ', '+QUOTENAME(Product) FROM #t FOR XML PATH ('')),1,1,'')
SELECT #ISNULLDyColumn=STUFF((SELECT DISTINCT ', '+'ISNULL('+QUOTENAME(Product)+',''0'')' +' AS '+QUOTENAME(Product) FROM #t FOR XML PATH ('')),1,1,'')
SELECT #SumCol=STUFF((SELECT DISTINCT ' + '+QUOTENAME(Product) FROM #t FOR XML PATH ('')),1,2,'')
SET #Sql='
SELECT *,('+#SumCol+') AS Total FROM
(
SELECT Payment,'+#ISNULLDyColumn+'
FROM
(
SELECT * FROM #t
)AS
SRC
PIVOT
(
SUM(AMOUNT) FOR Product IN ('+#DyColumn+')
) AS Pvt
)dt
'
PRINT #Sql
EXECUTE (#Sql)
Result
Payment A B C D Total
---------------------------------
Cash 19 0 0 42 61
Credit 0 39 26 0 65

Store values in different variables in SQL, separated by (Comma) ","

I need to separate values and store them in different variables in SQL,
for example
a='3100,3101,3102,....'
And the output should be
x=3100
y=3101
z=3102
.
.
.
create function [dbo].[udf_splitstring] (#tokens varchar(max),
#delimiter varchar(5))
returns #split table (
token varchar(200) not null )
as
begin
declare #list xml
select #list = cast('<a>'
+ replace(#tokens, #delimiter, '</a><a>')
+ '</a>' as xml)
insert into #split
(token)
select ltrim(t.value('.', 'varchar(200)')) as data
from #list.nodes('/a') as x(t)
return
end
GO
declare #cad varchar(100)='3100,3101,3102'
select *,ROW_NUMBER() over (order by token ) as rn from udf_splitstring(#cad,',')
token rn
3100 1
3101 2
3102 3
The results of the Parse TVF can easily be incorporated into a JOIN, or an IN
Declare #a varchar(max)='3100,3101,3102'
Select * from [dbo].[udf-Str-Parse](#a,',')
Returns
RetSeq RetVal
1 3100
2 3101
3 3102
The UDF if needed (much faster than recursive, loops, and xml)
CREATE FUNCTION [dbo].[udf-Str-Parse] (#String varchar(max),#Delimiter varchar(25))
Returns Table
As
Return (
with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (IsNull(DataLength(#String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a,cte1 b,cte1 c,cte1 d) A ),
cte3(N) As (Select 1 Union All Select t.N+DataLength(#Delimiter) From cte2 t Where Substring(#String,t.N,DataLength(#Delimiter)) = #Delimiter),
cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(#Delimiter,#String,s.N),0)-S.N,8000) From cte3 S)
Select RetSeq = Row_Number() over (Order By A.N)
,RetVal = LTrim(RTrim(Substring(#String, A.N, A.L)))
From cte4 A
);
--Orginal Source http://www.sqlservercentral.com/articles/Tally+Table/72993/
--Much faster than str-Parse, but limited to 8K
--Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')
I suggest you to use following query, it's much faster than other functions like cross apply and udf.
SELECT
Variables
,S_DATA
FROM (
SELECT
Variables
,CASE WHEN LEN(LIST2)>0 THEN LTRIM(RTRIM(SUBSTRING(LIST2, NUMBER+1, CHARINDEX(',', LIST2, NUMBER+1)-NUMBER - 1)))
ELSE NULL
END AS S_DATA
,NUMBER
FROM(
SELECT Variables
,','+COMMA_SEPARETED_COLUMN+',' LIST2
FROM Tb1
)DT
LEFT OUTER JOIN TB N ON (N.NUMBER < LEN(DT.LIST2)) OR (N.NUMBER=1 AND DT.LIST2 IS NULL)
WHERE SUBSTRING(LIST2, NUMBER, 1) = ',' OR LIST2 IS NULL
) DT2
WHERE S_DATA<>''
and also you should create a table 'NUMBER' before running the above query.
CREATE TABLE TB (Number INT)
DECLARE #I INT=0
WHILE #I<1000
BEGIN
INSERT INTO TB VALUES (#I)
SET #I=#I+1
END

How to dynamically count rows in a table from two another tables?

I want to count rows in CHAT table that their REASON_ID column exist in REASON_GROUP table:
First table Chat:
ID REASON_ID DEPARTMENT_ID
1 46 1
2 46 1
3 50 1
4 50 2
5 100 1
6 100 2
Second table Reason:
ID REASON_NAME REASON_GROUP_ID
46 Reason1 1
50 Reason2 1
100 Reason3 2
101 Reason4 2
105 Reqson5 3
Third table Reason_Group :
ID NAME
1 Group1
2 Group2
3 Group3
I want to display result like this:
Reason1 Reason2 Reason3 Reason4 Reason5
2 2 2 0 0
You can use PIVOT and dynamic sql for that:
DECLARE #DynamicPivotQuery AS nvarchar(max)
DECLARE #ColumnName AS nvarchar(max)
--Get distinct values of the PIVOT Column
SELECT #ColumnName = ISNULL(#ColumnName + ',', '') + QUOTENAME(REASON_NAME)
FROM (SELECT DISTINCT REASON_NAME FROM Reason) AS Reasons
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
N'SELECT ' + #ColumnName + ' FROM
(
SELECT r.REASON_NAME, SUM(CASE WHEN c.ID is null OR rg.ID IS NULL THEN 0 ELSE 1 END) AS cnt
FROM Reason r
LEFT JOIN Chat c ON (c.REASON_ID = r.ID)
LEFT JOIN Reason_Group rg ON (r.REASON_GROUP_ID = rg.ID)
GROUP BY REASON_NAME
) inn
PIVOT(AVG(cnt)
FOR REASON_NAME IN (' + #ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql #DynamicPivotQuery
Result:
Reason1 Reason2 Reason3 Reason4 Reqson5
2 2 2 0 0
Actually you can do it without PIVOT, but you still have to use dynamic sql, I do not know how you can resolve your task without dynamic sql :(
So this is a solution without PIVOTING:
DECLARE #DynamicQuery AS nvarchar(max)
DECLARE #AgrColumns AS nvarchar(max)
--Get distinct values of the Column
SELECT #AgrColumns = ISNULL(#AgrColumns + ',', '') + 'SUM(CASE WHEN REASON_NAME = ''' + REASON_NAME + ''' THEN cnt ELSE 0 END) AS ' + QUOTENAME(REASON_NAME)
FROM (SELECT DISTINCT REASON_NAME FROM Reason) AS Reasons
--Prepare the query using the dynamic
SET #DynamicQuery =
N'SELECT ' + #AgrColumns + ' FROM
(
SELECT r.REASON_NAME, SUM(CASE WHEN c.ID is null OR rg.ID IS NULL THEN 0 ELSE 1 END) AS cnt
FROM Reason r
LEFT JOIN Chat c ON (c.REASON_ID = r.ID)
LEFT JOIN Reason_Group rg ON (r.REASON_GROUP_ID = rg.ID)
GROUP BY REASON_NAME
) inn'
--Execute the Dynamic Query
EXEC sp_executesql #DynamicQuery

Comma Separated Values in SQL using Stored PRocedure

What i currently have is:
COUNT DETAILS:
CNT DTLID COUNT TOTAL QTY UNITPRICE AMOUNT
1 234 2222 1.20 32
1 12 123 2 21
What i want it to be like
CNT DTLID COUNT TOTAL QTY UNITPRICE AMOUNT
1 234,12 2222 , 123 1.20,2 32 + 21 = 53
I want to have comma Separated values and also want to use group by clause for amount column.
Currently What I`m upto is:
ALTER PROCEDURE [dbo].[sp_Tbl_CountDetail_SelectAll]
-- Add the parameters for the stored procedure here
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
select * from Tbl_CountDetail
inner join tbl_Contract
on
tbl_CountDetail.ContractID = tbl_Contract.ContractID
inner join tbl_Count
on
tbl_CountDetail.CountID = tbl_Count.CountID
where tbl_CountDetail.isDeleted = 0
and tbl_Contract.isdeleted = 0
END
Some friendly sample data
create table #CountDetails
(
DTLID int,
CNT int,
Qty int,
UnitPrice money,
Amount int
)
insert into #CountDetails
SELECT
1, 234, 2222, 1.20, 32
UNION ALL SELECT
1, 12, 123, 2, 21
Here's some code
SELECT
DTLIDs.DTLID,
CNTs =
ISNULL(
STUFF(
(
select ',' +
cast(CD.cnt as varchar(50))
from #CountDetails CD
where CD.DTLID = DTLIDs.DTLID
order by CD.CNT
FOR XML PATH('')
),
1, 1, '' --removes the leading ','
),
''
),
QTYs =
ISNULL(
STUFF(
(
select ',' +
cast(CD.qty as varchar(50))
from #CountDetails CD
where CD.DTLID = DTLIDs.DTLID
order by CD.Qty
FOR XML PATH('')
),
1, 1, '' --removes the leading ','
),
''
),
UnitPrices =
ISNULL(
STUFF(
(
select ',' +
cast(CD.UnitPrice as varchar(50))
from #CountDetails CD
where CD.DTLID = DTLIDs.DTLID
order by CD.UnitPrice
FOR XML PATH('')
),
1, 1, '' --removes the leading ','
),
''
),
AmountSum =
(
select SUM(Amount) from #CountDetails CD
where CD.DTLID = DTLIDs.DTLID
)
from (
select distinct DTLID from #CountDetails
) DTLIDs
There are various ways to tweak this. For example, the "AmountSum =" nested query code be done on a group by - I just like the more consistent look given the way the rest of the query is structured.
For the CSV lists, you didn't specify how you wanted it sorted. I've ordered by the values (eg ORDER BY CD.CNT) but you can change that to order by whatever you want. Similarly there are no spaces between the CSV values. You can tweak this by changing the select ',' to have a space in there and parameters to the STUFF command (change the second 1 to a 2).
Basically the FOR XML PATH('') bit takes the mini resultset its given and returns some text with no XML literals (due to the ''). This is tidied up using STUFF to remove the leading , at the start of the XML PATH result.
Hope this helps! :)
Can be done something like this....
DECLARE #VALUES NVARCHAR(1000),#UnitPrice nvarchar(100)
SELECT #VALUES = COALESCE(#VALUES + ',','') + CAST(COUNTQty AS NVARCHAR(50)),
#UnitPrice = COALESCE(#UnitPrice + ',','') + CAST(UnitPrice AS NVARCHAR(50)) FROM tableName
SELECT #VALUES as [CountQty],#Ids as [UnitPrice]
Have not checked group by price issue..!!

creating sql query for selecting multiple data

i need a sql query for my table tbl1
sample contents of the table like this
serial ida idb
1 1 2
2 1 3
3 3 7
4 3 6
5 2 4
6 2 6
.
in the table tbl1 column ida and idb are related like 1 is related with 2 and 3 , 2 is related with 4 and 6
ida value 1 s related data is 2 and 3 and i want to select the related data of 1' s related data (2 and 3).
2 and 3 s related data is 7, 6 and 4, 6. so the output will be (7,6,4)
. i need a sql query to display this out put. can anyone share some idea how to do that ..
SELECT DISTINCT idb FROM tbl1 WHERE ida = 2 OR ida = 3;
Is this what you were looking for?
EDIT: Corrected determining child branches of the hierarchy.
This may be of some use:
-- Sample data.
declare #Table as table ( serial int identity, ida int, idb int )
insert into #Table ( ida, idb ) values
( 1, 2 ), ( 1, 3 ),
( 3, 7 ), ( 3, 6 ),
( 2, 4 ), ( 2, 6 )
select * from #Table
-- Demonstrate recursive query.
; with CTE as (
-- Start with ida = 1.
select serial, ida, idb, 1 as depth, path = cast( right( '000000' + cast( ida as varchar(6) ), 6 ) as varchar(1024) )
from #Table
where ida = 1
union all
-- Add each row related to the most recent selected row(s).
select T.serial, T.ida, T.idb, C.depth + 1, cast( C.path + right( '000000' + cast( T.ida as varchar(6) ), 6 ) as varchar(1024) )
from CTE as C inner join
#Table as T on T.ida = C.idb
)
-- Show everything.
select *
from CTE
-- Repeat the recursive query.
; with CTE as (
-- Start with ida = 1.
select serial, ida, idb, 1 as depth, path = cast( right( '000000' + cast( ida as varchar(6) ), 6 ) as varchar(1024) )
from #Table
where ida = 1
union all
-- Add each row related to the most recent selected row(s).
select T.serial, T.ida, T.idb, C.depth + 1, cast( C.path + right( '000000' + cast( T.ida as varchar(6) ), 6 ) as varchar(1024) )
from CTE as C inner join
#Table as T on T.ida = C.idb
)
-- Select only the deepest children.
select distinct idb
from CTE as C
where not exists ( select 42 from CTE where left( path, len( C.path ) ) = C.path and len( path ) > len( C.path ))
order by idb
Left as an exercise is pivoting the result.
select distinct idb from tbl1 where ida in (select idb from tbl1 where ida = 1)