CSDN博客

img small_pig

存储过程实现BBS树形结构

发表于2001/8/13 13:25:00  532人阅读

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

0 0

相关博文

我的热门文章

img
取 消
img