分享
 
 
 

存储过程实现BBS树形结构

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

BBS的树形结构一直是大家讨论的话题,以前我做都是利用命名规则来实现,这样的好处是表的冗余字段少,结构清楚,容易理解,但其局限性也很明显。感谢廖家远提供算法(实话说,当年算法就没有学好),我决定采用一下这种算法来实现bbs的树形结构。基本思路如下:

bbs文章表中有这样几个字段:

RootID : 根ID , 新发贴子及其所有子贴都相同。

FatherID: 父ID , 父贴子ID

Layer: 层数 , 贴子在树中的深度。

OrderNum: 排序基数,关键所在,根据它来排序。

基本算法举例如下:

根16(拿个小的举例)

id ordernum Layer

1 16 0

2 16+16/2 1 回复第1贴

3 16+16/(2^2) 1 回复第1贴

4 16+16/2+16/(2^3) 2 回复第2贴

5 16+16/(2^2)+16/(2^4) 2 回复第3贴

然后,根据排序的结果是(加上回复的深度,就成了树状结构)

id ordernum 深度

1 16 0

3 16+16/(2^2) 1

5 16+16/(2^2)+16/(2^4) 2

2 16+16/2 1

4 16+16/2+16/(2^3) 2

成了这样的树:

1

3

5

2

4

根据以上思路,我们设计表如下:

/*BBS文章表*/

if exists (select * from sysobjects where ID = object_id("BBS"))

drop table BBS

go

create table BBS

(

ID int primary key identity not null ,

RootID int default 0 not null ,

FatherID int default 0 not null ,

Layer tinyint default 0 not null ,

ForumID int default 0 not null ,

UserID int default 0 not null ,

Title varchar(255) default "" not null ,

Content text default "" ,

PostTime datetime default getdate() not null ,

FaceID tinyint default 0 not null ,

TotalChilds int default 0 not null ,

OrderNum float default power(2,30) not null ,

Hits int default 0 not null ,

selected bit default 0 not null ,

closed bit default 0 not null ,

IfEmail bit default 0 not null ,

IfSignature bit default 0 not null

)

go

/*BBS注册用户表*/

if exists(select * from sysobjects where ID = object_id("BBSUser"))

drop table BBSUser

go

create table BBSUser

(

ID int Primary key identity not null ,

UserName varchar(20) default "" not null ,

Password varchar(10) default "" not null ,

UserType tinyint default 0 not null , --用户类型,1为斑竹

Email varchar(100) default "" not null ,

HomePage varchar(100) default "" not null ,

ICQ varchar(20) default "" not null ,

Signature varchar(255) default "" not null , --签名

Point int default 0 not null , --用户积分

)

go

表结构定了,剩下的就是怎样实现。我把所有相关的功能集成在一个存储过程中,包括贴子本身的存储,其关键是排序基数的生成;父贴子相关字段的更新 ; 根贴相关字段的更新,这些都放到一个事务中,以保持数据的一致性,另外如果父贴要求有回复用email通知,在存储过程中实现发回复email的功能,而不必借助任何asp或其他的组件。这样就使所有任务在一个存储过程中实现。

--------------------------------------------------------------------------------

下面是上篇文章所说的存储过程,其作用已经说过,在这里就不再赘述了。请大家自己看代码吧。这个存储过程只是存储数据的过程,以后如果有时间我将讲一下读取数据。

/**********************************************************************/

/* */

/* Stored Procudure : up_PostTopic */

/* */

/* Description: 贴子存储及回复Email */

/* */

/* Author: Bigeagle */

/* */

/* date: 2000/7/25 凌晨 */

/* */

/* History: version 1.0 by BigEagle , 2000/7/25 */

/* */

/**********************************************************************/

if exists (select * from sysobjects where id = object_id("up_PostTopic"))

drop proc up_PostTopic

go

create proc up_PostTopic @a_intID int OUTPUT ,

@a_intFatherID int , @a_intForumID int , @a_intUserID int ,

@a_strTitle varchar(255) , @a_strContent text , @a_intFaceID tinyint ,

@a_bIfEmail bit , @a_bIfSignature bit

as

declare @m_intTopicID int

declare @m_intLayer tinyint

declare @m_intRootID int

declare @m_fOrderNum float

select @m_fOrderNum = power(2 , 30) --初始化排序基数

/*首先判断是否有这个论坛,没有则退出*/

if not exists (select * from BBSCategory where CategoryID = @a_intForumID)

begin

select @a_intID = 0

return(0)

end

/*判断是新发贴子还是回应主题*/

if @a_intFatherID = 0 --没有父贴子,说明是新发贴子

select @m_intLayer = 1 , @m_intRootID = 0

else

begin

if not exists(select * from BBS where ID = @a_intFatherID) --如果没发现父贴子

begin

select 'TopicID' = 0

return (0)

end

else --如果发现父贴子,则取出层数和根ID

select @m_intLayer = Layer + 1 ,@m_intRootID = RootID ,@m_fOrderNum = OrderNum

from BBS where ID = @a_intFatherID

end

/*更新表,因为要对多个表操作,所以放到事务里*/

begin transaction

/*插入表BBS*/

insert into BBS (FatherID , Layer , ForumID , UserID , Title ,

Content , PostTime , FaceID , Hits , selected ,

closed , IfEmail , IfSignature , OrderNum)

values(@a_intFatherID , @m_intLayer , @a_intForumID , @a_intUserID , @a_strTitle ,

@a_strContent , getdate() , @a_intFaceID , 0 , 0 ,

0 , @a_bIfEmail , @a_bIfSignature , default)

if (@@error <> 0) goto On_Error --如果出错转向错误处理部分

select @m_intTopicID = @@identity --取出刚刚插入纪录的ID

/*如果是新发贴子则取ID为RootID*/

if @m_intRootID = 0 --新发贴子

begin

select @m_intRootID = @m_intTopicID

end

else --不是新发贴子则更新根纪录的TotalCounts

begin

update BBS set TotalChilds = TotalChilds + 1 --更新根的子贴数

where ID = @m_intRootID

if (@@error <> 0) goto On_Error --如果更新失败则转向错误处理部分

end

select @m_fOrderNum = @m_fOrderNum + power(2,30)/power(2,TotalChilds)

from BBS where ID = @m_intRootID

select @m_fOrderNum

/*更新RootID , OrderNum*/

update BBS set OrderNum = @m_fOrderNum , RootID = @m_intRootID

where ID = @m_intTopicID

if (@@error <> 0) goto On_Error --如果更新失败则转向错误处理部分

/*更新BBSCategory表*/

update BBSCategory set TopicCounts = TopicCounts + 1 , LastReplyTime = getDate()

where CategoryID = @a_intForumID

if (@@error <>0) goto On_Error --如果更新失败则转向错误处理部分

/*更新BBSUser表,将用户分数加一*/

update BBSUser set Point = Point + 1

where ID = @a_intUserID

/*如果全部成功则完成事务*/

commit transaction

/*如果要求回复则发邮件*/

declare @m_strEmail varchar(100) , @m_bIfEmail bit

declare @m_strName varchar(20) , @m_strSubject varchar(50)

declare @m_strMessage varchar(255)

select @m_bIfEmail = a.IfEmail , @m_strEmail = IsNull(b.Email , ""),

@m_strName = b.UserName

from BBS as a

left join BBSUser as b on a.UserID = b.ID

where a.ID = @a_intFatherID

select @m_strSubject = "来自eMatter Board : 您有回复"

select @m_strMessage = "您发表在eMatter Board的贴子现在有人回复:"

+ " http://server1/bbs/showtopic.asp?ID="

+ convert(varchar,@a_intFatherID)

if @m_StrEmail <> "" and @m_bIfEmail = 1

exec master..xp_sendmail @recipients = @m_strEmail , @subject = @m_strSubject,

@message = @m_strMessage

select @a_intID = @m_intTopicID --返回贴子ID

return (0)

On_error: --错误处理部分

rollback transaction

select @a_intID = 0 --贴子ID返回0,代表失败

return (-1)

go

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有