在SQL Server中,我有一个具有多级层次结构的表:
[Id Ctg Art] [Desc Ctg] [Id nodo]
1 GRANDI ELETTRODOMENSTICI 0
3 PICCOLI ELETTRODOMESTICI 0
15 INCASSO 0
7 CONSERVAZIONE 1
35 Lavaggio e asciugatura 1
18 Frigoriferi 7
44 Frigoriferi 7
32 DOPPIA PORTA 18
82 MONO PORTA 44
我想通过一个查询来获得像这样的单个记录:
1;Grandi Elettrodomestici;Conservazione;Frigoriferi;Doppia Porta
1;Grandi Elettrodomestici;Conservazione;Frigoriferi;Mono Porta
我设法使用两个子例程和两个嵌套查询来获得结果,但是我认为可以通过一个SQL命令获得相同的结果。
第一子:
Public Sub CTG()
Dim db As Database, RS As Recordset, h, i, j, k, SQL As String
Dim ID As Integer, S As String, RS_C As Recordset
Set db = CurrentDb
SQL = "SELECT Categorie.[Id nodo], Categorie.[Id Ctg Art] "
SQL = SQL & "From Categorie WHERE (((Categorie.[Id nodo]) = 0)) "
SQL = SQL & "ORDER BY Categorie.[Id Ctg Art];"
Set RS_C = db.OpenRecordset(SQL, dbOpenDynaset)
Do Until RS_C.EOF
SQL = "SELECT Categorie.[Id nodo], Categorie.[Desc Ctg], Categorie.[Id Ctg Art] "
SQL = SQL & "From Categorie WHERE (((Categorie.[Id nodo]) = 0) "
SQL = SQL & "And Categorie.[Id Ctg Art] = " & RS_C![Id Ctg Art] & ") "
SQL = SQL & "ORDER BY Categorie.[Id Ctg Art];"
Set RS = db.OpenRecordset(SQL, dbOpenDynaset)
Do Until RS.EOF
ID = RS![Id Ctg Art]
S = RS![Id Ctg Art]
Call CTG_S(ID, S)
RS.MoveNext
Loop
RS_C.MoveNext
Loop
End Sub
第二子:
Public Sub CTG_S(ID As Integer, ByVal S As String)
Dim SQL As String, RS As Recordset, db As Database, SS As String
SS = S
Set db = CurrentDb
SQL = "SELECT Categorie.[Id nodo], Categorie.[Desc Ctg], Categorie.[Id Ctg Art] "
SQL = SQL & "From Categorie WHERE (((Categorie.[Id nodo]) = " & ID & ")) "
SQL = SQL & "ORDER BY Categorie.[Id Ctg Art];"
Set RS = db.OpenRecordset(SQL, dbOpenDynaset)
Do Until RS.EOF
ID = RS![Id Ctg Art]
S = SS & " - " & ID
MsgBox S
Call CTG_S(ID, S)
RS.MoveNext
S = SS
Loop
End Sub
答案 0 :(得分:1)
以下代码演示了使用递归CTE遍历层次结构的一种方法。通过将最后的select
语句替换为备用语句,您可以显示中间结果以了解其工作原理。
-- Sample data.
declare @Samples as Table ( IdCtgArt Int, DescCtg VarChar(32), IdNodo Int );
insert into @Samples ( IdCtgArt, DescCtg, IdNodo ) values
( 1, 'GRANDI ELETTRODOMENSTICI', 0 ),
( 3, 'PICCOLI ELETTRODOMESTICI', 0 ),
( 15, 'INCASSO', 0 ),
( 7, 'CONSERVAZIONE', 1 ),
( 35, 'Lavaggio e asciugatura', 1 ),
( 18, 'Frigoriferi', 7 ),
( 44, 'Frigoriferi', 7 ),
( 32, 'DOPPIA PORTA', 18 ),
( 82, 'MONO PORTA', 44 );
select * from @Samples;
-- Build the tree.
with
LeafNodes as (
-- Get the leaf nodes, i.e. those with no children.
select IdCtgArt, DescCtg, IdNodo
from @Samples as SP
where not exists ( select 42 from @Samples as SC where SC.IdNodo = SP.IdCtgArt ) ),
Tree as (
-- Start at the leaf nodes ...
select IdCtgArt, DescCtg, IdNodo, IdCtgArt as LeafId, 0 as Depth, Cast( DescCtg as VarChar(1024) ) as Path
from LeafNodes as LN
union all
-- ... and work up one level at a time adding parents.
select S.IdCtgArt, S.DescCtg, S.IdNodo, T.LeafId, T.Depth + 1, Cast( S.DescCtg + ', ' + T.Path as VarChar(1024) )
from Tree as T inner join
@Samples as S on S.IdCtgArt = T.IdNodo
),
InterestingRows as (
-- Interesting rows are those that start from the leaf nodes and have the maximum depth.
select LeafId, Max( Depth ) as MaxDepth
from Tree as T
where T.LeafId in ( select IdCtgArt from LeafNodes )
group by LeafId )
-- The result is interesting rows which have a depth greater than zero, i.e. leaf nodes with at least one level of parent.
select T.IdCtgArt, T.Path
from Tree as T inner join
InterestingRows as IR on IR.LeafId = T.LeafId and IR.MaxDepth = T.Depth
where T.Depth > 0;
-- Replace the final select with one of these statements to see the intermediate results:
-- select * from LeafNodes;
-- select * from Tree;
-- select * from InterestingRows;
这确实会产生一个额外的输出行:1, 'GRANDI ELETTRODOMENSTICI, Lavaggio e asciugatura'
。目前尚不清楚为什么您的样本数据会排除该行。