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
  • 相关阅读:
    [TJOI2019]大中锋的游乐场——最短路+DP
    [TJOI2019]甲苯先生的滚榜——非旋转treap
    [TJOI2019]甲苯先生的字符串——矩阵乘法+递推
    [TJOI2019]唱、跳、rap和篮球——NTT+生成函数+容斥
    [ZJOI2020]字符串
    Ubuntu 20.04 工作区小记
    2020省选犯傻记
    寒假到省选的一些笔记
    AtCoder tokiomarine2020 题解
    [CF1336E]Chiori and Doll Picking
  • 原文地址:https://www.cnblogs.com/wzq806341010/p/3452050.html
Copyright © 2011-2022 走看看