查询具有多级数据的表

时间:2019-05-11 22:22:19

标签: sql sql-server tsql

在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 

1 个答案:

答案 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'。目前尚不清楚为什么您的样本数据会排除该行。