zoukankan      html  css  js  c++  java
  • 无限级菜单操作(存储过程、游标、递归、事务)修改版

    /**递归删除菜单**/
    if exists (select * from sysobjects where name='proc_menu_P_delete')
    drop proc proc_menu_P_delete
    go
    create proc proc_menu_P_delete(@id int)
    as 
    declare @count int,@tmpid int,@err int
    select @count=count(1) from tb_menu where pId=@id--通过父Id获得子集数据
    if(@count>0)--判断是否存在子集数据
    begin 
        --根据父Id获得子集并将子集数据Id保存到游标中
        declare ar_cursor cursor local for select id from tb_menu where pid=@id
        open ar_cursor--打开游标
        fetch next from ar_cursor into @tmpid  --取值
        /**@@FETCH_STATUS是MSSQL的一个全局变量(0:FETCH 语句成功,-1:FETCH 语句失败或此行不在结果集中,-2:被提取的行不存在
        @@fetch_status值的改变是通过fetch next from实现的,“FETCH NEXT FROM Cursor”)**/
        while @@FETCH_STATUS=0
        begin 
            exec proc_menu_P_delete @tmpid--将游标中的子集Id作为参数调用存储过程(递归)
            --递归出来以后将游标中的下一个Id赋值给变量
            fetch next from ar_cursor into @tmpid
        end
            close ar_cursor
            deallocate ar_cursor
    end 
    delete tb_menu where Id=@id
    go
    
    /**删除菜单**/
    if exists (select * from sysobjects where name='proc_menu_delete')
    drop proc proc_menu_delete
    go
    create proc proc_menu_delete(@id int)
    as
    begin
        declare @cNum int,@pId int
        begin try
            begin tran
            select @cNum=-(CNum+1),@pId=pId from tb_Menu where Id=@id
            exec proc_menu_updatecNum @pId,@cNum--修改父节点的子节点个数
            exec proc_menu_P_delete @id--删除自身及其子节点
            commit tran
        end try
        begin catch
            rollback tran
        end catch
    end
    go
    
    /**修改父节点的子节点数量**/
    if exists (select * from sysobjects where name='proc_menu_updatecNum')
    drop proc proc_menu_updatecNum
    go
    create proc proc_menu_updatecNum(@pId int,@cNum int)
    as
    declare @tmpId int,@_pId int
        select @_pId=pId from tb_menu where id=@pId
    if(@_pId<>0)
    begin
        declare cor_CNum cursor local for select pId from tb_menu where id=@pId
        open cor_CNum
        fetch next from cor_CNum into @tmpId
        while @@FETCH_STATUS=0
        begin
            exec proc_menu_updatecNum @tmpId,@cNum
            fetch next from cor_CNum into @tmpId
        end
        close cor_CNum
        deallocate cor_CNum
    end    
    update tb_Menu set cNum=cNum+@cNum where id=@pId
    go
    
    
    /**修改子节点的深度**/
    if exists (select * from sysobjects where name='proc_menu_updateLevel')
    drop proc proc_menu_updateLevel
    go
    create proc proc_menu_updateLevel(@id int,@level int)
    as
    begin
        declare @tmpid int,@count int
        select @count=COUNT(1) from tb_Menu where pId=@id
        if(@count<>0)
            begin
                declare cur_level cursor local for select id from tb_menu where pId=@id
                open cur_level
                fetch next from cur_level into @tmpid
                while(@@FETCH_STATUS=0)
                    begin
                        exec proc_menu_updateLevel @tmpid,@level
                        fetch next from cur_level into @tmpid
                    end
                close cur_level
                deallocate cur_level
            end
        update tb_Menu set level=level+@level where Id=@id
    end
    go
    
    /**修改节点顺序:针对Jquery的zTree控件的拖动节点排序功能**/
    if exists (select * from sysobjects where name='proc_menu_updateSort')
    drop proc proc_menu_updateSort
    go
    create proc proc_menu_updateSort(@id int,@newpId int,@sibId int,@dir int)
    as
     begin
        /**
        @id:被移动的节点,@newpId:新父节点,@sibId:新父节点下的兄弟节点,@dir:方向,移动目标前面:1,移到后面:-1
        假设:原节点父节点为1,兄弟节点值以及顺序为:5,4,3,2,1,目标父节点为2,兄弟节点值以及顺序为:3,2,1
              a:现将原节点4,移动到父节点为2的子节点2的“前”面  改变后的值为:
                原:5,4,3,2,1  =>(移走3并且将大于3的减1)=> 4,3,2,1
                新:3,2,1 =>(将大于2的节点加1)=>4,2,1 =>(新插入的排序为:目标节点排序值+1)=>4,3(插入值),2,1
              b:现将原节点4,移动到父节点为2的子节点2的“后”面  改变后的值为:
                原:5,4,3,2,1  =>(移走3并且将大于3的减1)=> 4,3,2,1
                新:3,2,1 =>(将大于等于2的节点加1)=>4,3,1 =>(新插入的排序为:目标节点排序值+1)=>4,3,2(插入值),1
        **/
        begin try
          begin tran
                --修改原兄弟节点的顺序,大于被移走的节点全部-1
                declare @oldsort int,@oldpId int,@cNum int,@level int
                select @oldsort=sort,@oldpId=pId,@cNum=CNum,@level=level from tb_Menu where Id=@id
                update tb_Menu set sort=sort-1 where sort>@oldsort and pId=@oldpId
                if(@sibId<>0)--是否指定了兄弟节点
                    begin
                    --修改新兄弟节点的顺序、修改移动后自己节点顺序
                    declare @newsort int,@sibIdsort int
                    --获得目标节点的排序,并将目标节点的父节点重新付给传进来的@newpId(防止参数@newpId传错)
                    select @sibIdsort=sort,@newpId=pId from tb_Menu where Id=@sibId
                    if(@dir=1)--移动到目标节点的前面
                    begin
                        update tb_Menu set sort=sort+1 where pId=@newpId and sort>@sibIdsort
                        update tb_Menu set sort=@sibIdsort+1 where id=@id
                    end
                    else if(@dir=-1)
                    begin
                        update tb_Menu set sort=sort+1 where pId=@newpId and sort>=@sibIdsort
                        update tb_Menu set sort=@sibIdsort where Id=@id
                    end
                end
                else if(@newpId<>0 and @sibId=0)--直接移动某个父节点最下面,即没有选中目标兄弟节点
                    begin
                    update tb_Menu set sort=sort+1 where pId=@newpId
                    update tb_Menu set sort=1 where Id=@id
                end
                
                if(@newpId<>@oldpId)--判断是否改变了父节点
                    begin
                    declare @newpLevel int
                    set @cNum=@cNum+1
                    if(@newpId<>0)
                    begin
                        select @newpLevel=level from tb_Menu where id=@newpId
                    end
                    else
                    begin
                        set @newpLevel=0
                    end
                    update tb_Menu set pId=@newpId where Id=@id
                    declare @levelCount int
                    PRINT @newpLevel
                    set @levelCount=@newpLevel+1-@level
                    exec proc_menu_updateLevel @id,@levelCount
                    exec proc_menu_updatecNum @newpId,@cNum
                    set @cNum=-(@cNum)
                    exec proc_menu_updatecNum @oldpId,@cNum
                end
            commit tran
        end try
        
        begin catch
            rollback tran
        end catch
     end
    go
    
    /**新增节点**/
    if exists (select * from sysobjects where name='proc_menu_add')
    drop proc proc_menu_add
    go
    create proc proc_menu_add(@name varchar(50),@pId int,@id int output)
    as
    begin
        begin try
            begin tran
                declare @pLevel int
                if(@pId<>0)
                begin
                    select @pLevel=level+1 from tb_Menu where Id=@pId
                end
                else
                begin
                    set @pLevel=1
                end
                insert into tb_Menu(name,twoname,pId,level,cNum,state,sort,dt,url,des)
                values(@name,'',@pId,@pLevel,0,1,0,getdate(),'','')
                set @id=@@IDENTITY
                select @id
                update tb_Menu set sort=sort+1 where pId=@pId--兄弟元素排序加1
                exec proc_menu_updatecNum @pId,1--修改父节点的子节点数量
            commit tran
        end try
        begin catch
            set @id=0
            rollback tran
        end catch
    end
    go
    
    /**根据节点获得所有子节点数据**/
    --方法1:连接查询
    if exists (select * from sysobjects where name='proc_menu_select')
    drop procedure proc_menu_select
    go
    create proc proc_menu_select(@id int)
    as
        declare @i int 
        declare @count int, @tmpid int
        create table #tb(
                    id int,
                    name varchar(50),
                    twoname varchar(50),
                    pId int,
                    level int,
                    state int,
                    sort int,
                    url varchar(100)
                    )
        select @count=COUNT(1) from tb_Menu where pId=@id
        select @i=level-1 from tb_Menu where pId=@id
        insert #tb select m.id,m.name,m.twoname,m.pId,m.level,m.state,m.sort,m.url from tb_Menu m where pId=@id
                while(@count<>0)
                    begin
                    set @i=@i+1
                      select @count=COUNT(1) from tb_Menu m left join #tb on #tb.id=m.pId where #tb.level=@i
                      insert #tb select m.id,m.name,m.twoname,m.pId,m.level,m.state,m.sort,m.url from tb_Menu m
                       left join #tb on #tb.id=m.pId where #tb.level=@i
                    end    
                select id,name,twoname,pId,level,state,sort,url from #tb order by sort desc
    go
    
    --方法2:递归查询
    if exists(select * from sysobjects where name='proc_menu_sele')
    drop proc proc_menu_sele
    go
    create proc proc_menu_sele(@id int,@t int)
    as
        if(@t<>0)
            begin
            declare @tmppId int
            select @tmppId=pId from tb_Menu where Id=@id
            create table #tab(
                    id int,
                    name varchar(50),
                    twoname varchar(50),
                    pId int,
                    level int,
                    state int,
                    sort int,
                    url varchar(100)
                    )
            end
        declare @tmpid int,@count int
        select @count=COUNT(1) from tb_Menu where Id=@id
        if(@count<>0)
            begin
            insert INTO  #tab select id,name,twoname,pId,level,state,sort,url from tb_Menu where Id=@id
            declare cur_select cursor local for select id from tb_menu where pId=@id
            open cur_select
            fetch next from cur_select into @tmpid
            while(@@FETCH_STATUS=0)
                begin
                exec proc_menu_sele @tmpid,0
                fetch next from cur_select into @tmpid
                end
            close cur_select
            deallocate cur_select
            end
        else
            begin
            insert INTO  #tab select id,name,twoname,pId,level,state,sort,url from tb_Menu where Id=@id
            end
        declare @p int
        select @p=pId from tb_Menu where Id=@id
            if(@p=@tmppId)
            begin
                select * from #tab order by sort desc
            end
    go
  • 相关阅读:
    分层图最短路(DP思想) BZOJ2662 [BeiJing wc2012]冻结
    动态规划 BZOJ1925 地精部落
    线性DP SPOJ Mobile Service
    线性DP codevs2185 最长公共上升子序列
    数位DP POJ3208 Apocalypse Someday
    线性DP POJ3666 Making the Grade
    杨氏矩阵 线性DP? POJ2279 Mr.Young's Picture Permutations
    tarjan强连通分量 洛谷P1262 间谍网络
    树链剖分 BZOJ3589 动态树
    二分图 BZOJ4554 [Tjoi2016&Heoi2016]游戏
  • 原文地址:https://www.cnblogs.com/wzq806341010/p/3452050.html
Copyright © 2011-2022 走看看