http://expert.csdn.net/Expert/topic/1375/1375432.xml?temp=.1278345-----------select 
len(dbo.FN_32getsubclass(tc_id,default,default))-len(replace(dbo.FN_32getsubclass(tc_id,default,default),',',''))+1 as counts
,* from treeclass

解决方案 »

  1.   

    用函数加遞歸可以很好解決:
      CREATE FUNCTION howmany  (@f int,@s int)
    RETURNS int AS  
    BEGIN declare @id int , @pid intDECLARE TreeC  CURSOR local FOR 
    SELECT id,parentid 
    FROM Tree
    where parentid=@fOPEN TreeC
    FETCH NEXT FROM TreeC
    INTO @ID,@PID
    WHILE @@FETCH_STATUS = 0
    begin
    set @s=@s+1
    set @s=dbo.howmany(@id,@s)FETCH NEXT FROM TreeC
    INTO @ID,@PIDendCLOSE TreeC
    DEALLOCATE TreeC
    return @s
    END
    --- then execselect f1,  dbo.howmany(f1,0) as qty from
    (select distinct f1 from T) A
      

  2.   

    ---had tested!----test data:
    create table  Tree (ID [Integer],ParentID [Integer],Re [varchar])INSERT INTO Tree (ID,ParentID) 
           SELECT 1,0
        UNION ALL
           SELECT 2,1
        UNION ALL
           SELECT 3,1
        UNION ALL
           SELECT 4,2
        UNION ALL
           SELECT 5,4
        UNION ALL
           SELECT 6,5
        UNION ALL
           SELECT 7,2create table T(F1 int)
     INSERT INTO T (F1)
           SELECT 1 union all
     SELECT 2
        
        UNION ALL
           SELECT 5
        UNION ALL
           SELECT 3
        UNION ALL
           SELECT 4
        UNION ALL
           SELECT 1
        UNION ALL
           SELECT 7
        UNION ALL
           SELECT 6
        UNION ALL
           SELECT 4
        UNION ALL
           SELECT 5
        UNION ALL
           SELECT 3
        UNION ALL
           SELECT 4
        UNION ALL
           SELECT 1
        UNION ALL
           SELECT 7
        UNION ALL
           SELECT 6
        UNION ALL
           SELECT 4---- exec 
    select f1,  dbo.howmany(f1,0) as qty from
    (select distinct f1 from T) A
    ---- exec result
    ID      qty
    1 6
    2 4
    3 0
    4 2
    5 1
    6 0
    7 0
        
      

  3.   

    drop table #temp1
    select A.*, isnull(B.cnt,0) as cnt into #temp1  from tree as A left join (select f1, count(*) as cnt from T group by f1) as B on A.id = B.f1
    declare @i int
    declare @cnt int
    select @i = max(id) from #temp1
    while @i > 0 
    begin
      select @cnt=cnt from #temp1 where id = @i
      update #temp1 set cnt = cnt + @cnt where id in (select parentid from #temp1 where id = @i)
      set @i = @i - 1
    end
    select id, cnt from #temp1id          cnt         
    ----------- ----------- 
    1           15
    2           10
    3           2
    4           8
    5           4
    6           2
    7           2(7 row(s) affected)
      

  4.   

    UDF 是应该用的!
    临时表 游标 还是免了吧!
      

  5.   

    做TREE一般id,parentID就够了,不过我还是建议多加几个字段:
    id  parentid  level interid
    1 0     1     1
    2 1     2     1.2
    3 1     2     1.3
    4 2     3     1.2.4
    5 4     4     1.2.4.5
    6 5     5     1.2.4.5.6
    7 2     3     1.2.7
    再以这种结构去做查询,语句简单很多,效率也会高些。这样的表结构也不难维护。
    如果这我上面写的这样的结构,语句就很简单了。
      

  6.   

    做TREE一般id,parentID就够了,不过我还是建议多加几个字段:
    id  parentid  level interid
    1 0     1     1
    2 1     2     1.2
    3 1     2     1.3
    4 2     3     1.2.4
    5 4     4     1.2.4.5
    6 5     5     1.2.4.5.6
    7 2     3     1.2.7
    再以这种结构去做查询,语句简单很多,效率也会高些。这样的表结构也不难维护。
    如果把表做成我上面写的这样的结构,语句就很简单了。
      

  7.   

    如果表结构象我写的那样,只需要一句:
    select id,
    (select count(*) 
    from t t2 join tree t1 on t2.f1=t1.id
    where left(t1.interid,len(t0.interid))=t0.interid
    )
    from tree t0
    就可以搞定。
      

  8.   

    create function GetSum(@id int)
    returns int
    as
    begin
    declare @sum int
    declare @a table(id int)
    insert @a select @idwhile exists(
    select 1 
    from @a a,tree b 
    where a.id=b.parentid 
    and b.id not in (select id from @a))insert @a 
    select b.id 
    from @a a,tree b 
    where a.id=b.parentid 
    and b.id not in (select id from @a)select @sum=count(*) from @a a,T b where a.id=b.f1
    return @sum
    end
    select id,dbo.getSum(id) from tree
      

  9.   

    /*
    看了前几个人的答案,似乎都把问题想复杂了"游标"、"临时表"、"递归"。
    "游标"、"临时表" 完全可以不用!
    "递归" 思想当然应是解决树型结构的该想到的方法!
    但是 T-SQL 的嵌套层次最多只能到 32!
    icevi(按钮工厂) 的建议是非常值得提倡的,尽管 ID,ParentID 对于仅存储是足够经济的,
    但是若用其提供表现形式,性能的确不会太好!
    许多高效的树型结构论坛也确实是存储并维护各个节点的层次信息的数据,这样
    显示起来仅需一条 SQL 即可!
    下面是我的参考答案,两个自定义函数功能几乎一样,都是运算出前面所提的,
    应最好主动维护的"层次信息":方法一: UDF 递归实现! 有 32 层嵌套限制
    */alter  FUNCTION dbo.Get32Ancestors
    (@X integer)
    RETURNS VARCHAR(250)
    AS
    BEGIN
    DECLARE @ID integer
    DECLARE @ReturnValue VARCHAR(250)SELECT TOP 1 @ID = ParentID
    FROM tree 
    WHERE id=@XIF @ID <> @X
       BEGIN
         SELECT @ReturnValue  = cast(ISNULL(dbo.Get32Ancestors(@ID),'') as varchar) + '-'+ cast(@X as varchar)
       END
    ELSE SET @ReturnValue = @IDRETURN @ReturnValue
    ENDgo
    /*
    方法二: 无任何限制,若层次太深,效率当然不会高(好像也没更好的办法)
    */
    alter function GetAllAncestors (@X integer)
    returns varchar(1000)
    as
    begin
    declare @ReturnValue  varchar(1000)
    declare @ID integer
    declare @ParentID integer select top 1 @ID=isnull([ID],0),@ParentID = isnull([ParentID],0)
    from tree
    where ID = @Xwhile @id <> @parentid 
    begin
        if  len(ltrim(rtrim(isnull(@ReturnValue,'')))) >0
            set @ReturnValue = '-' +isnull(@ReturnValue,'') 
        set @ReturnValue= cast(@id as varchar) + isnull(@ReturnValue,'')
        select top 1 @ID=isnull([ID],0),@ParentID = isnull([ParentID],0)
          from tree
         where ID = @parentid
        if @parentid = 0 
           break
    endreturn(cast(@id as varchar) + '-' + @ReturnValue)
    end
    go/*
    方法一是"高手"的惯性思维把简单的问题搞复杂了,"太累"!
    方法二是思路简单清晰,不但是"菜鸟"首选,"高手"也应反思!若是本题分为两问:
    1.求各节点层次信息
    2.求属各节点含后代的记录数可能大家就会受到一些启发!
    函数定义完,下面就应该和 icevi(按钮工厂) 同志的答案异曲同工、不谋而和了
    */select id,dbo.GetAllAncestors(id)
           ,(select count(*) 
               from T 
              where '-' + dbo.GetAllAncestors(f1) + '-' like '%-' + cast(tree.id as varchar) + '-%') 
    from treeselect id,dbo.Get32Ancestors(id)
           ,(select count(*) 
               from T 
              where '-' + dbo.Get32Ancestors(f1) + '-' like '%-' + cast(tree.id as varchar) + '-%') 
    from tree/* 
    另外还要说一下封装的程度的问题,具体情况具体分析,
    本题就不适合定义函数直接得到最终结果!
    以上答案仅供参考!!
    欢迎继续参与讨论!
    */
      

  10.   

    declare @ table(id int)
    insert @ values (4)while exists(select 1 from @ a,tree b where a.id=b.parentid and not exists (select 1 from @ where id=b.id))
      insert @ select b.id from @ a,tree b where a.id=b.parentid and not exists (select id from @ where id=b.id)select * from @个人认为是树的最佳解法!
      

  11.   

    两种方法的特点不同,倒推的方法快,而正找的方法(找下级)如果TREE表记录多了,也相当慢,因为分支节点多。(而倒推省去找分技,只找上级)但是实际中,tree表记录不多,
    T表记录是无尽的,可能几百万或上千万。倒推的方法最后根动不了。
      

  12.   

    /*
    方法二: 无任何限制,若层次太深,效率当然不会高(好像也没更好的办法)
    改进了一下:
    1.断码不会死循环
    2.GetAllAncestors(不存在的节点)返回NULL
    3.GetAllAncestors(根节点)返回自己 
    */
    alter function GetAllAncestors (@X integer)
    returns varchar(1000)
    as
    begin
    declare @ReturnValue  varchar(1000)
    declare @ID integer
    declare @ParentID integer set @ID = -1select top 1 @ID=isnull([ID],0),@ParentID = isnull([ParentID],0)
    from tree
    where ID = @Xwhile @id <> @parentid and @parentid <> 0 and @ID >0
      begin
        if  @ReturnValue is not null
            set @ReturnValue = '-' + @ReturnValue
        set @ReturnValue= cast(@id as varchar) + isnull(@ReturnValue,'')
        set @id = -1
        --set @parentid = -2
        select top 1 @ID=isnull([ID],0),@ParentID = isnull([ParentID],0)
          from tree
         where ID = @parentid
      endset @ReturnValue = '-' + @ReturnValueif @ID > 0
       set @ReturnValue = cast(@id as varchar) + isnull(@ReturnValue,'')
    return(@ReturnValue)
    --select dbo.GetAllAncestors(500)
    end
      

  13.   

    我在文档中心也贴了一个:
    一道 SQL 题 ... (关于树型结构的在关系表中的存储及其应用处理)
    http://www.csdn.net/Develop/read_article.asp?id=17247欢迎捧场"点击"!
      

  14.   

    小干部:
      我还是坚持原来的看法且做了测试:
    -----***环境***---
    delete t
    delete tree
    declare @number int,@v int
    set @number=0
    while @number<1000
      begin
        set @v=cast(rand(checksum(newid()))*5 as int)+1
        while @v>0
          begin
            insert t values(@number+1)
            set @v=@v-1
          end
        insert tree values(@number+1,@number,null)
      set @number=@number+1
      end
    --------------------------------------------
    --------****所用三个方法**--------------
    create function GetSum(@id int)
    returns int
    as
    begindeclare @ table(id int)
    declare @sum int
    insert @ values(@id)while exists(select 1 from @ a,tree b where a.id=b.parentid and not exists (select 1 from @ where id=b.id))
      insert @ select b.id from @ a,tree b where a.id=b.parentid and not exists (select 1 from @ where id=b.id)
    select @sum=count(*) from T where exists (select 1 from @ where id=T.F1)
    return @sum
    end
    go
    ----调用:
    select *,dbo.GetSum(id) from tree
    -------------------------------------------------
    CREATE function GetAllAncestors (@X integer)
    returns varchar(1000)
    as
    begin
    declare @ReturnValue  varchar(1000)
    declare @ID integer
    declare @ParentID integer set @ID = -1select top 1 @ID=isnull([ID],0),@ParentID = isnull([ParentID],0)
    from tree
    where ID = @Xwhile @id <> @parentid and @parentid <> 0 and @ID >0
      begin
        if  @ReturnValue is not null
            set @ReturnValue = '-' + @ReturnValue
        set @ReturnValue= cast(@id as varchar) + isnull(@ReturnValue,'')
        set @id = -1
        --set @parentid = -2
        select top 1 @ID=isnull([ID],0),@ParentID = isnull([ParentID],0)
          from tree
         where ID = @parentid
      endset @ReturnValue = '-' + @ReturnValueif @ID > 0
       set @ReturnValue = cast(@id as varchar) + isnull(@ReturnValue,'')
    return(@ReturnValue)
    --select dbo.GetAllAncestors(500)
    end
    -------调用:
    select id,(select count(*) from t t2 join tree t1 on t2.f1=t1.id where left(dbo.GetAllAncestors(t1.id),len(dbo.GetAllAncestors(t0.id)))=dbo.GetAllAncestors(t0.id)) from tree t0
    ---------------------------------------------------------------
    if object_id('tempdb..#temp1') is not null drop table #temp1
    select A.*,isnull(B.cnt,0) cnt into #temp1  from tree as A left join (select f1,count(*) cnt from T group by f1) as B on A.id = B.f1
    declare @i int
    declare @cnt int
    select @i=max(id) from #temp1
    while @i>0 
    begin
      select @cnt=cnt from #temp1 where id = @i
      update #temp1 set cnt = cnt + @cnt where id in (select parentid from #temp1 where id = @i)
      set @i=@i-1
    end
    select id, cnt from #temp1
    --------------------------------------------------------
    --****P3 800 512M win2kas sql2k企业 下结果****----
    -------------------getsum---------GetAllAncestors--------临时表
    --tree有50条记录: 0:00:04          0:00:13               0:00:00
    --tree有60条记录: 0:00:06          0:00:22               0:00:00
    --tree有70条记录: 0:00:10          0:00:38               0:00:00
    --tree有70条记录: 0:00:14          0:01:00               0:00:00
    --tree有1000条记录:不敢测           不敢测                0:00:03
      

  15.   

    GetAllAncestors速度慢是慢在它的函数内部和引用大量字符函数
      

  16.   

    小干部的是倒推找,它省去找多头分支节点,只有一支。
    主要的问题是:
      实际中,TREE表记录有限不多,而T表记录很多,可能是TREE表的上百倍。
    所以他的方法,函数运不仅要在TREE表运行,在T表也要。
    相当慢(我测试过)。
      优点是比起临时表来,内存用的要少点。适合于记录量很少的情况用。
      

  17.   

    2003-3-5
    方法二: 无任何限制,若层次太深,效率当然不会高(好像也没更好的办法)
    改进了一下:
    1.正常节点均从0显示! 0-1-32.断码 显示 -7-8-9-10
    3.GetAllAncestors(不存在的节点)返回NULL
    4.GetAllAncestors(根节点)返回 0-自己 
    5.死循环点显示: 4-5-6-4-8alter function GetAllAncestors (@X integer)
    returns varchar(1000)
    as
    begin
    declare @ReturnValue  varchar(1000)
    declare @ID integer
    declare @ParentID integer set @ID = -1select top 1 @ID=isnull([ID],0),@ParentID = isnull([ParentID],0)
    from tree
    where ID = @Xwhile @id <> @parentid and @parentid <> 0 and @ID >0
          and '-' + isnull(@ReturnValue,'') +'-' not like '%-' + cast(@id as varchar) + '-%' 
      begin
        if  @ReturnValue is not null
            set @ReturnValue = '-' + @ReturnValue
        set @ReturnValue= cast(@id as varchar) + isnull(@ReturnValue,'')
        set @id = -1
        select top 1 @ID=isnull([ID],0),@ParentID = isnull([ParentID],0)
          from tree
         where ID = @parentid
      endset @ReturnValue = '-' + @ReturnValueif @id>0 
       set @ReturnValue = cast(@id as varchar) + isnull(@ReturnValue,'')if @parentid =0 or  @id = @parentid
       set @ReturnValue = '0-'  + isnull(@ReturnValue,'')   return(@ReturnValue)
    --select dbo.GetAllAncestors(10)
    end
      

  18.   

    BEST TIP!!
    Got it~~~