存储过程实现BBS树形结构

原创 2001年08月13日 13:25:00

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

树形结构的数据库实现,存储过程实现添加删除查询功能

USE [JPKCDB] GO /****** Object:  StoredProcedure [dbo].[BbsDelete]    Script Date: 2015/11/19 23:3...
  • jiao_zg
  • jiao_zg
  • 2015年11月19日 23:51
  • 663

18-Oracle学习_存储过程-递归-树状结构的存储与展示

一, 表 create table article ( id number primary key, cont varchar2(4000), pid number, ...
  • wuqinfei_cs
  • wuqinfei_cs
  • 2013年08月22日 22:41
  • 1215

树形结构的数据库表设计

树形结构的数据库表设计 程序设计过程中,我们常常用树形结构来表征某些数据的关联关系,如企业上下级部门、栏目结构、商品分类等等,通常而言,这些树状结构需要借助于数据库完成持久化。然而目前的各种基于关系...
  • cb2474600377
  • cb2474600377
  • 2016年03月25日 14:15
  • 2010

树形结构的数据如何保存到关系型的数据库

需求: 文档型数据,结构是树形的,如图: 想要读取生成树形结构、添加子节点、查找修改数据的代价最小。 看知乎上牛人的答案: 一般比较普遍的就是四种方法:(具体见 SQL Ant...
  • jim8757
  • jim8757
  • 2016年08月31日 15:41
  • 3565

pl/sql存储过程的递归调用,树形数据的展示

--pl/sql的树状结构的存储与展示 drop table article; create table article( id number primary key, --id cont v...
  • u010689306
  • u010689306
  • 2016年06月01日 00:46
  • 1622

数据结构之树的三种存储结构

说道存储结构,我们就会
  • x1247600186
  • x1247600186
  • 2014年04月28日 23:36
  • 30217

Java数据结构-树及树的存储结构

树的定义:n(n>=0)个节点的有限集。 n=0时称为空树。 n!=0时为非空树,有且仅有一个特定的节点——根;n>1时,其它节点可以分为m(m>0)个互不相交的有限集T1~Tm,其中每一个集合本身又...
  • yannanying
  • yannanying
  • 2015年07月23日 00:06
  • 2317

mysql存储树形结构的数据

分析树形数据JSON格式的树形结构数据需要保存到mysql中。树形图如下: 分析成文本如图: 存到表中的结构为: 需求一般树形结构的数据使用需求有两点:显示整棵树的数据select * fr...
  • q383965374
  • q383965374
  • 2017年12月03日 23:46
  • 328

树形结构的实现

做项目的时候有这样的需求,我们需要在下拉列表中把部门的结构以树形结构的形式给显示出来。原型如下: 我们的架构是SSH(struts2),下面将实现过程(代码都是一些核心代码)和大家分享: 一、代...
  • hxj135812
  • hxj135812
  • 2015年11月24日 13:29
  • 289

树形菜单 的mysql 存储过程实现增删查

添加:入参:IN nodename VARCHAR(50),IN pageUrl VARCHAR(50),IN type INT,IN pid INT BEGIN   DECLARE declLI...
  • jiao_zg
  • jiao_zg
  • 2015年12月30日 17:42
  • 716
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:存储过程实现BBS树形结构
举报原因:
原因补充:

(最多只允许输入30个字)