有两个这样的有,其中一张表是用来保存学生信息,叫材料信息表(ID,name)分别代表材料号和材料名称。
   另一个表是这样的(ID1,ID2,COUNT),ID1表示材料1,ID2表示材料2,COUNT为材料1包含材料2的个数 。
   ID1    ID2   COUNT
   4001   4002    2
   4001   4003    3
   4001   4004    4
   4002   4005    5
   4002   4006    2
   上图说明了,材料4001由2个4002构成、3个4003构成、4个4004构成。材料4002由5个4005构成、2个4006构成。
   就是说4001由4002构成,而4002又由4005构成,4005又可能还有其下级构成。
   现在我想查出材料4001的全部构造情况,这应该涉及到递归过程,请问这样的递归该如何写呢?
   小弟不盛感激!!!!!如能给出具体代码更好!

解决方案 »

  1.   

    又见此帖。继续顶
    create proc abc
    @id1 varchar(20)
    As
    declare @layer int
    begin    create table #temptable(
            Id1 varchar(20) null,
            Id2 varchar(20) null,
            Level1 int null,
            [count] int default 0,
            )    set @layer = 0  
        insert into #temptable select id1,id2,@layer,[Count] from 你的表 where id1=@id1
        while (@@RowCount>0)
        begin
          Set @Layer=@Layer+1
          insert into #TempTable 
           select @id1,a.id2,@layer,b.[count]*a.[Count] from 你的表 a join #TempTable b
           on a.id1=b.id2 where b.level1=@layer-1
        end
        select @id1,id2,sum([count]) from #tempTable group by id2
        Drop Table #TempTable
    end
      

  2.   

    前几天给一个朋友写了个小程序,执行界面如
    http://www.sundyn.com/floor.jpg和楼主的问题性质差不多,可以看看。
      

  3.   

    那你能不能把源代码给我看看?我的e-mail:[email protected]。不胜感激!
      

  4.   

    我的建议
    根据level1也就是层数递增排序(这样就保证了将要键的节点的父节点已经建立好了,就是这个道理)
    然后循环纪录集在treeview上建树下面的是递归建树的方法不建议用
    库里需要一条有总结点的纪录
    ‘全部节点' '产品1'
    调用
    BuildBomTree(‘全部节点',nil,Treeview1);
    procedure TFrm_Pro_BomTree.BuildBomTree(AId: string; ParentNode: TTreeNode;
      temp_treeview: Ttreeview);
    var
      QryTmp: TADOQuery;
      myNode: TTreeNode;
      myLabel: TLabel;
    begin
      QryTmp := TADOQuery.Create(nil);
      qrytmp.connection := Dm_Main.Database_Cs;
      QryTmp.SQL.Add('select * from pro_bom');
      QryTmp.SQL.Add('where cp_peij_no=:AId');
      qrytmp.Parameters.ParamByName('aid').value := aid;
      QryTmp.Open;
      while not QryTmp.Eof do
      begin
        myNode := temp_Treeview.Items.AddChild(ParentNode, QryTmp.fieldbyname('wl_peij_no').AsString + ':' +
                  Dm_Pro_Shuju.Return_PeiJMc(QryTmp.fieldbyname('wl_peij_no').AsString));
               //ReturnNodeText(QryTmp.fieldbyname('wl_peij_no').AsString));这句不用了
                 //创建标签,caption存放各分支的AutoId表识
        myLabel := TLabel.Create(Application);
        myLabel.Visible := False;
        myLabel.Caption := QryTmp.fieldbyname('wl_peij_no').AsString;
        myNode.Data := myLabel;
        BuildBomTree(QryTmp.fieldbyname('wl_peij_no').Asstring, myNode, temp_treeview); //递归用过程
        QryTmp.Next;
      end;
      QryTmp.Free;
    end;
      

  5.   

    to qizhanfeng(glacier) 那如果用你的那种方法,如何读到树中,要怎么写呢?
      

  6.   

    借助一个中间表,通过表的联接可以很高效的解决这个问题,在SQL版有这样的问题,找找吧
      

  7.   

    --如果你的节点编码有规律如101,10101,其中10101是101的子节点
    --那么直接按递增排序然后按我下面写的建树过程的其中一部分套用就行--如果编码没有规律那么只能按层排序后建树
    --以下的就是,当然也适合编码有规律的情况
    --我用存储过程返回按层排序的数据集
    --创建测试表
    create table t_test(
    sParent varchar(20),
    sChild varchar(20),
    iCount int
    constraint Pk_t_test primary key(sParent,sChild) )
    --插入测试数据
    insert into t_test select 'A','B',2
    union select 'A','C',3
    union select 'C','D',2
    union select 'C','E',4--创建"返回按层排序数据集"的存储过程
    create proc p_sort(@sParent varchar(20))
    as
    begin
      declare @l int  --记录层
      create table #t(  --返回按层排序数据集
        sParent varchar(20),
        sChild  varchar(20),
        L       int not null default(0),
        primary key (sParent,sChild))
      set @l = 0
      insert into #t select '',@sParent,@l 
      while @@rowcount > 0 
      begin
        set @l=@l+1
        insert into #t select b.sChild,a.sChild,@l 
         from t_test a inner join #t b on a.sParent=b.sChild
        where L=@l-1
      end
      select * from #t order by L
      return 0
    end--调用存储过程
    exec p_sort 'A'  --返回按层排序数据集
    /*测试结果
    sParent              sChild               L           
    -------------------- -------------------- ----------- 
                         A                    0
    A                    B                    1
    A                    C                    1
    C                    D                    2
    C                    E                    2(所影响的行数为 5 行)*///delphi程序实现
    //窗体上放 button1,adoconnection1, ADOStoredProc1,TreeView1
    //ADOStoredProc1的connection连接  adoconnection1
    //button1的点击事件里写
    procedure TForm1.Button1Click(Sender: TObject);
    function MakeTree(sParent:String):Boolean;
    var
      nodeCur:TTreeNode;
      sPrt,sCld:String;
    begin
      nodeCur:=nil;
      with ADOStoredProc1 do
      try
        Close;
        ProcedureName:= 'p_sort;1';
        Parameters.Refresh;
        Parameters.ParamByName('@sParent').Value:=sParent;
        Open;
        if Parameters.ParamByName('@return_value').Value<>0 then Abort;
        First;
        while not eof do
        begin
          sPrt:=FieldByName('sParent').AsString;
          sCld:=FieldByName('sChild').AsString;
          if sPrt='' then nodeCur:=TreeView1.Items.AddChild(nil,sCld)
          else
          begin
            while nodeCur.Text<>sPrt do
               nodeCur:=nodeCur.Parent;
            nodeCur:=TreeView1.Items.AddChild(nodeCur,sCld);
          end;
          Next;
        end;
      except
        showmessage('出错!');
        raise;
      end;
      result:= true;
    end;
    begin
      TreeView1.Items.Clear;
      TreeView1.Items.BeginUpdate;
      MakeTree('A');
      TreeView1.Items.EndUpdate ;
      TreeView1.FullExpand;
    end;
      

  8.   

    楼上的对
    包含 Transact-SQL 语句或批处理的 Unicode 字符串,stmt 必须是可以隐式转换为 ntext 的 Unicode 常量或变量。不允许使用更复杂的 Unicode 表达式(例如使用 + 运算符串联两个字符串)。不允许使用字符常量。如果指定常量,则必须使用 N 作为前缀。例如,Unicode 常量 N'sp_who' 是有效的
      

  9.   

    我寫好了。希望幫得上忙。 qizhanfeng(glacier) ( ) 信誉:100 這個朋友寫的我不太懂:)unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls, Db, ADODB;type
      TForm1 = class(TForm)
        ADOConnection1: TADOConnection;
        ADOQuery1: TADOQuery;
        Button1: TButton;
        Edit1: TEdit;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;
    function parts_stru (x_id:string):string;implementation{$R *.DFM}function parts_stru (x_id:string):string;
    var qr_temp:TADOquery;
        x_name:string;
        s:string;
    begin
      s:='';
      qr_temp:=TADOquery.create(nil);
      qr_temp.Connection :=form1.ADOConnection1 ;
      with qr_temp do
        begin
          close;
          sql.clear;
          sql.Add('select * from table2');
          sql.add('where id=:id');
          parameters[0].value:=x_id;
          open;
          if not isempty then
              x_name:=fieldbyname('name').asString
          else
            begin
              showmessage('不存在此材料');
              form1.close;
            end;
          close;
          sql.clear;
          sql.add('select * from table1');
          sql.add('where id1=:id1');
          parameters[0].value:=x_id;
          open;
          if not isempty then
            begin
              first;
              while not eof do
                begin
                  s:=s+fieldbyname('count').asString+'*('+parts_stru(fieldbyname('id2').asString)+')+';
                  next;
                end;
              result:=copy(s,1,length(s)-1);
            end
          else
            result:=trim(x_name);
        end;
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      edit1.Text :=parts_stru('4001');
    end;end.
     
    記得給我分:)
      

  10.   

    楼主,我已经将程序发到 [email protected] 
    请查收。
      

  11.   

    我想问一下qizhanfeng,如果SQL返回的是这样的结果,用的方法好像读到树中,那么树的顺序就错了.
    sParent              sChild               L           
    -------------------- -------------------- ----------- 
                         A                    0
    A                    B                    1
    A                    C                    1    
    B                    D                    2   -----把C改为B  
    B                    E                    2   -----把C改为B
       读到第三条记录时,nodecur.text为C,那么你在读第四条记录时,根据你的程序好像不会把D、E读到B节点下面。
      

  12.   

    不明白
    “把C改为B”是什么意思
    临时表里存放的节点就是用ADOStoredProc1建树的那个例子的节点sChild字段的父节点就是t_test表的父节点,存放在临时表的sParent字段
      

  13.   

    constraint Pk_t_test primary key(sParent,sChild) )
    --插入测试数据
    insert into t_test select 'A','B',2
    union select 'A','C',3
    union select 'B','D',2
    union select 'B','E',4
    如果你把临时表t_test改成上面形式,就会出错,不信你自己试一下。
      

  14.   

    怎么答案看着那么乱啊,楼主去DB2或者ORANCLE去看看,递归表的SQL语句自己在看看,手头没SQL SERVER,没办法帮你查