树形数据的处理
发表于:2007-07-02来源:作者:点击数:
标签:
描述:讨论如何处理树形数据,排序,新增,修改,复制,删除,数据完整性检查,汇总统计 表结构描述及数据环境: 表名tb,如果修改表名,则相应修改所有数据处理中涉及到的表名tb id为编号(标识字段+主键),pid为上级编号,name为名称,后面可以自行增加其他字段. 凡
描述:讨论如何处理树形数据,排序,新增,修改,复制,删除,数据完整性检查,汇总统计
表结构描述及数据环境:
表名tb,如果修改表名,则相应修改所有数据处理中涉及到的表名tb
id为编号(标识字段+主键),pid为上级编号,name为名称,后面可以自行增加其他字段.
凡是未特殊标注的地方,对自行增加的字段不影响处理结果/*--数据
测试环境 表名tb,如果修改表名,则相应修改所有数据处理中涉及到的表名tb
id为编号(标识字段+主键)
pid为上级编号
name为名称,后面可以自行增加其他字段.
凡是未特殊标注的地方,对自行增加的字段不影响处理结果
--表环境
create table tb(id int identity(1,1) not null constraint PK_tb primary key clustered
,pid int,name varchar(20))
insert into tb
select 0,@#中国@#
union all select 0,@#美国@#
union all select 0,@#加拿大@#
union all select 1,@#北京@#
union all select 1,@#上海@#
union all select 1,@#江苏@#
union all select 6,@#苏州@#
union all select 7,@#常熟@#
union all select 6,@#南京@#
union all select 6,@#无锡@#
union all select 2,@#纽约@#
union all select 2,@#旧金山@#
go
--处理中需要使用的函数及存储过程
--1.自定义函数--获取编码累计
create function f_getmergid(@id int)
returns varchar(8000)
as
begin
declare @re varchar(8000),@pid int
--为了数字排序正常,需要统一编码宽度
declare @idlen int,@idheader varchar(20)
select @idlen=max(len(id))
,@idheader=space(@idlen)
from tb
--得到编码累计
set @re=right(@idheader+cast(@id as varchar),@idlen)
select @pid=pid from tb where id=@id
while @@rowcount>0
select @re=right(@idheader+cast(@pid as varchar),@idlen)+@#,@#+@re
,@pid=pid from tb where id=@pid
return(@re)
end
go
--2.自定义函数--检测某个编码出发,是否被循环引用
create function f_chkid(@id int)
returns bit --循环,返回1,否则返回0
as
begin
declare @re bit,@pid int
set @re=0
--检测
select @pid=pid from tb where id=@id
while @@rowcount>0
begin
if @pid=@id
begin
set @re=1
goto lbErr
end
select @pid=pid from tb where id=@pid
end
lbErr:
return(@re)
end
go
/*--数据复制
如果表中包含自定义字段,需要修改存储过程
存在嵌套不超过32层的问题.
--*/
--3.复制指定结点下的子结点到另一个结点下
create proc p_copy
@s_id int, --复制该项下的所有子项
@d_id int, --复制到此项下
@new_id int --新增加项的开始编号
as
declare @nid int,@oid int,@name varchar(20)
select id,name into #temp from tb where pid=@s_id and id<@new_id
while exists(select 1 from #temp)
begin
select @oid=id,@name=name from #temp
insert into tb values(@d_id,@name)
set @nid=@@identity
exec p_copy @oid,@nid,@new_id
delete from #temp where id=@oid
end
go
--4.批量复制的存储过程--复制指定结点及其下面的所有子结点,并生成新结点
create proc p_copystr
@s_id varchar(8000) --要复制项的列表,用逗号分隔
as
declare @nid int,@oid int,@name varchar(20)
set @s_id=@#,@#+@s_id+@#,@#
select id,name into #temp from tb
where charindex(@#,@#+cast(id as varchar)+@#,@#, @s_id)>0
while exists(select 1 from #temp)
begin
select @oid=id,@name=name from #temp
insert into tb values(@oid,@name)
set @nid=@@identity
exec p_copy @oid,@nid,@nid
delete from #temp where id=@oid
end
go
--6.得到指定id的子id列表
create function f_getchildid(@id int)
returns @re table(id int)
as
begin
insert into @re select id from tb where pid=@id
while @@rowcount>0
insert into @re select a.id
from tb a inner join @re b on a.pid=b.id
where a.id not in(select id from @re)
return
end
go
--7.得到指定id的父id列表
create function f_getparentid(@id int)
returns @re table(id int)
as
begin
declare @pid int
select @pid=pid from tb where id=@id
while @pid<>0
begin
insert into @re values(@pid)
select @pid=pid from tb where id=@pid
end
return
end
go
--8.删除指定结点
create proc p_delete
@id int, --要删除的id
@deletechild bit=0 --是否删除子 1.删除子,0.如果@id有子,则删除失败.
as
if @deletechild=1
delete from tb where dbo.f_getmergid(id) like dbo.f_getmergid(@id)+@#%@#
else
if exists(select 1 from tb where pid=@id)
goto lbErr
else
delete from tb where id=@id
return
lbErr:
RAISERROR (@#该结点下有子结点,不能删除@#, 16, 1)
go
--9.得到编码累计及编码级别表,这个是针对全表的,主要是应该于全表处理:
create function f_getbmmerg()
returns @re table(id int,idmerg varchar(8000),level int)
as
begin
declare @idlen int,@idheader varchar(20), @level int
select @idlen=max(len(id)),@idheader=space(@idlen) from tb
set @level=1
insert into @re select id,right(@idheader+cast(id as varchar),@idlen),@level
from tb where pid=0
while @@rowcount>0
begin
set @level=@level+1
insert into @re select b.id,a.idmerg+@#,@#+right(@idheader+cast(b.id as varchar),@idlen),@level
from @re a inner join tb b on a.id=b.pid
where a.level=@level-1
end
return
end
go
--应用:
/*--数据显示排序--*/
--分级显示--横向,先一级,后二级...
select * from tb order by pid
--分级显示--纵向
select * from tb order by dbo.f_getmergid(id)
go
/*--数据统计--*/
--分级统计,每个地区下的明细地区数
select *,
明细地区数=(select count(*) from tb where dbo.f_getmergid(id) like dbo.f_getmergid(a.id)+@#,%@#)
from tb a order by dbo.f_getmergid(id)
go
/*--数据新增,修改
数据新增,修改(包括修改所属的类别)没有什么技巧
,只需要检查所属的上级是否存在就行了.这个可以简单的用下面的语句来解决:
if exists(select 1 from tb where id=@id) print @#存在@# else print @#不存在@#
--*/
--删除@#美国@#的数据
--exec p_delete 2 --不包含子,因为有美国下有子,所以删除会出错
exec p_delete 2,1 --包含子,将删除美国及所有数据
go
原文参见我在CSDN上发表的贴子
http://expert.csdn.net/Expert/topic/2285/2285830.xml?temp=.1212885
原文转自:http://www.ltesting.net