不规则树算法(SQL Server)

 
SQL:不规则树算法(SQL Server)

有如下的数据,parentid表示父节点id,totalchilren表示该节点有几个子节点,total表示数量
id filecode parentid total children total
1  ws112           0       3         0
2  01              1       1         2
3  02              1       1         2
4  03              1       1         2
5  0101            2       0         3
6  0201            3       0         3
7  0301            4       0         3


     我们想输入ws112,得到如下的结果:
     0101  6(2*3)
     0201  6(2*3)
     0301  6(2*3)
     即不管01、02、03这些节点,直接得到ws112最低级的节点情况,请各位帮忙了。

     讨论一:
create table A
(
   id int,
   filecode varchar(10),
   parentid int,
   totalchildren int,
   total int
)
insert A select 1,'ws112',0,3,0
insert A select 2,'01',1,1,  2
insert A select 3,'02',1,1,  2
insert A select 4,'03',1,1,  2
insert A select 5,'0101',2,0,  3
insert A select 6,'0201',3,0,  3
insert A select 7,'0301',4,0,  3

create Function Find_num(@Code varchar(10))
returns @A table(filecode varchar(10),num int)
as
begin
declare @T table(id int,filecode varchar(10),parentid int,totalchildren int,total int,lev int,num int)
declare @lev int
set @lev=1
  insert @T select id,filecode,parentid,totalchildren,total,@lev as lev,@lev as num from A where filecode=@Code
while @@rowcount>0
begin
   set @lev=@lev+1
   insert @T select A1.id,A1.filecode,A1.parentid,A1.totalchildren,A1.total,@lev,A1.total*T.num  from A A1, (select * from @T where lev=@lev-1) T where T.id=A1.parentid
end
insert @A select T.filecode,T.num from @T T where T.lev=(select top 1 lev from @T order by lev DESC )
return
end

select * from dbo.Find_num('ws112')


      点评:例子好像只能实现规则的树,应该说,这个例子是特例,其实你的树是一颗不规则的树,叶子的深度可能不一样.你想想实现的目标是:
      1、查找到任一节点的全部叶子;
      2、然后每一个叶子到目标节点之间的所有节点的total值相乘;
       0101  6(2*3)
       0201  6(2*3)
       0301  6(2*3)
    
      讨论二:
create table A
(
   id int,
   filecode varchar(10),
   parentid int,
   totalchildren int,
   total int
)
insert A select 1,'ws112',0,3,0
insert A select 2,'01',1,1,  2
insert A select 3,'02',1,1,  2
insert A select 4,'03',1,1,  2
insert A select 5,'0101',2,0,  3
insert A select 6,'0201',3,0,  3
insert A select 7,'0301',4,0,  3
insert A select 8,'04',1,0,5

create function List_Leaf(@filecode varchar(10))
returns @LeafDetail table(filecode varchar(10),num int)
As
begin
declare @TempTable table(id int, filecode varchar(10),parentid int,totalchildren int,total int,lev int,num int)
declare @level int
set @level = 0
insert @TempTable select *,@level,1 from A where filecode = @filecode
while @@RowCount>0
begin
set @level = @level + 1
insert @TempTable select A.*,@level,A.total*(T.num) from @TempTable T,A where T.lev = @level-1 and A.parentid = T.id
end
insert @LeafDetail select filecode,num  from @TempTable where totalchildren  = 0
return
end

select * from List_Leaf('ws112')
go

测试结果:
filecode   num        
---------- -----------
04         5
0101       6
0201       6
0301       6

(所影响的行数为 4 行)


      点评:
办法实现了需要的功能,不过,用了两个临时表,效率方面让人有点不满意.


     讨论三:

create table filedir (
   id int,
   filecode varchar(10),
   pid int,
   totalchildren int,
   total int
)
insert filedir select 1,'ws112',0,3,0
insert filedir select 2,'01',1,1,  2
insert filedir select 3,'02',1,1,  2
insert filedir select 4,'03',1,1,  2
insert filedir select 5,'0101',2,0,  3
insert filedir select 6,'0201',3,0,  3
insert filedir select 7,'0301',4,0,  3
insert filedir select 8,'0401',1,0,  2
go

--创建用户定义函数
create function f_getChild(@ID VARCHAR(10))
returns @t table(ID VARCHAR(10),PID VARCHAR(10),Level INT)
as
begin
    declare @i int,@ret varchar(8000)
    set @i = 1
    insert into @t select ID,pid,@i from filedir where pid = @ID
    
    while @@rowcount<>0
    begin
        set @i = @i + 1
        
        insert into @t
        select
            a.ID,a.PID,@i
        from
            filedir a,@t b
        where
            a.PID=b.ID and b.Level = @i-1
    end
    return
end
go

create   function  f_getparenttotal(@id int,@topid int)
returns int
as
begin
declare   @pid   int
declare   @re    int
set @re=1
select   @pid=pid   from   filedir   where   id=@id
while    @pid>@topid
begin
select   @pid=pid,@re=@re*[total]   from   filedir   where   id=@pid
end
return @re
end
go

--执行查询,dbo.f_getparenttotal(id,1)和f_getChild(1)代表根节点id

select id,filecode,bb=dbo.f_getparenttotal(id,1)*total from filedir  where id in( select ID from  dbo.f_getChild(1) where id not in(select pid from filedir))

go

drop function f_getparenttotal
drop function f_getChild
drop table filedir




      点评: 此办法考虑到了功能的实现和执行的效率问题,但这是SQL Server2000的传统思维,下面介绍一下SQL Server 2005在这方面的应用:

--SQL Sever 2005 用(公共表表达式,实现递归方法)如下:

--测试环境
create table A
(
   id int,
   filecode varchar(10),
   parentid int,
   totalchildren int,
   total int
)
insert A select 1,'ws112',0,3,0
insert A select 2,'01',1,1,  2
insert A select 3,'02',1,1,  2
insert A select 4,'03',1,1,  2
insert A select 5,'0101',2,0,  3
insert A select 6,'0201',3,0,  3
insert A select 7,'0301',4,0,  3
insert A select 8,'04',1,0,5

--建递归CTE
DECLARE @FILECODE AS VARCHAR(20)
SET @FILECODE='ws112';
WITH ACTE(ID,FILECODE,PARENTID,TOTALCHILDREN,TOTAL,LVL)
AS
(
Select ID,FILECODE,PARENTID,TOTALCHILDREN,TOTAL,0
FROM A Where FILECODE=@FILECODE
UNION ALL
Select TA.ID,TA.FILECODE,TA.PARENTID,TA.TOTALCHILDREN,TA.TOTAL,TB.LVL+1
FROM A TA INNER JOIN ACTE TB
    ON TA.PARENTID=TB.ID
)
Select FILECODE,值=TOTAL*LVL FROM ACTE Where TOTALCHILDREN=0

--结果
/*
FILECODE   值
---------- -----------
04         5
0301       6
0201       6
0101       6

(4 行受影响)
*/
--删除环境 Drop table A
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值