求一个存储过程,功能是删除树上的一个结点,完成后立即加分。
我写的有点多了,其实没有什么,我就是想表达清楚一些,思路也比较清楚。
脚本如下:
create table Users 
(Userid integer,
 UserName varchar(20),
  LeftNode varchar(20),
  rightNode varchar(20)
)
goINSERT INTO [Users]
([UserID], [UserName], [LeftNode], [RightNode])
select 1, 'a', 'b', 'c'
union all
select 2, 'b', 'd', 'e'
union all
select 3, 'c', 'f', 'g'
union all
select 4, 'd', 'h','i'
union all
select 5, 'e', 'j', 'k'
union all
select 6, 'f', null, null
union all
select 7, 'g', null, 'l'
union all
select 8, 'h', null, null
union all
select 9, 'i', null, null
union all
select 10, 'j', null, null
union all
select 11, 'k', null, null
union all
select 12, 'l', null, null
goselect * from usersdrop table users
--以上是脚本表达的树应该是这样的:
            a
      b           c
  d      e      f   g
h   i  j   k           l上面就是语句里的这稞树
在删除的时候,有几种情况:
1:不考虑这个树最顶的结点删除的情况。
2:叶子结点:
   比如说要删除h,要先删除h,再把d的左子结点置空,
   即delete from users where UserName='h'
     update users set Leftnode=null where username='d'
3:非叶子结点:
  比如说要删除e.
  先删除E,再用j代替e的位置,然后把k放在j的最右下的位置
            a
      b           c
  d      j      f   g
h   i       k          l
  过程应该是下面这个样子,
   delete from users where username='e'
   update users set RightNode='j' where userName='b'
   update users set Rightnode='k' where UserName='j'  如果要删除的结点只有一边有子结点,把它删除,同时,把它下面的结点直接朝上提就可以了
  比如说要删除g,
这时,delete from users set UserName = 'g'
     update Users set rightNode='l' where UserName='c'麻烦把上面的过程写成存储过程,多谢

解决方案 »

  1.   


    群号: 25725864  
    名字: 程序↑人生?⑶
    要求: ORCALE和SQL SEEVER 高手进 热心人进  你的指点将使你我他茅舍顿开
      

  2.   

    if object_id('Users') is not null
        drop table Users
    if object_id('spTest') is not null
        drop proc spTest
    GO
    ----创建测试数据
    create table Users(Userid integer,UserName varchar(20),LeftNode varchar(20),rightNode varchar(20))
    GO
    INSERT INTO [Users]([UserID], [UserName], [LeftNode], [RightNode])
    select 1, 'a', 'b', 'c' union all
    select 2, 'b', 'd', 'e' union all
    select 3, 'c', 'f', 'g' union all
    select 4, 'd', 'h','i'union all
    select 5, 'e', 'j', 'k' union all
    select 6, 'f', null, null union all
    select 7, 'g', null, 'l' union all
    select 8, 'h', null, null union all
    select 9, 'i', null, null union all
    select 10, 'j', null, null union all
    select 11, 'k', null, null union all
    select 12, 'l', null, null 
    GO
    --select * from users
    GO
    ----创建存储过程
    create proc spTest @UserName varchar(20)
    as
    ----删除叶节点
    if exists(select 1 from users where UserName = @UserName and LeftNode is null and RightNode is null)
    begin
        delete users where UserName = @UserName
        update users set 
        LeftNode = case LeftNode when @UserName then NULL else LeftNode end,
        RightNode = case RightNode when @UserName then NULL else RightNode end
    end
    else
    begin
        declare @LeftNode varchar(20),@RightNode varchar(20)
        ----删除含有左右二个节点的非叶节点
        if exists(select 1 from users where UserName = @UserName and LeftNode is not null and RightNode is not null)
        begin        
            select @LeftNode = LeftNode,@RightNode = RightNode from users where UserName = @UserName
            --提升
            update users set 
            LeftNode = case LeftNode when @UserName then @LeftNode else LeftNode end,
            RightNode = case RightNode when @UserName then @LeftNode else RightNode end
            --更新
            update users set LeftNode = NULL,RightNode = @RightNode where UserName = @LeftNode
            --删除
            delete users where UserName = @UserName
        end
        ----删除只含有一个子节点的非叶节点
        if exists(select 1 from users where UserName = @UserName and (LeftNode is null or RightNode is null))
        begin
            set @LeftNode = null
            set @RightNode = null
            select @LeftNode = LeftNode,@RightNode = RightNode from users where UserName = @UserName
            set @LeftNode = isnull(@LeftNode,@RightNode)
            --提升
            update users set 
            LeftNode = case LeftNode when @UserName then @LeftNode else LeftNode end,
            RightNode = case RightNode when @UserName then @LeftNode else RightNode end
            --删除
            delete users where UserName = @UserName
        end
    end
    GO
    ----测试
    exec spTest 'h'
    exec spTest 'e'
    exec spTest 'g'
    ----查看
    select * from users----清除测试环境
    drop table users
    drop proc spTest/*结果
    Userid  UserName   LeftNode   rightNode
    ------------------------------------------------
    1       a          b          c
    2       b          d          j
    3       c          f          l
    4       d          NULL       i
    6       f          NULL       NULL
    9       i          NULL       NULL
    10      j          NULL       k
    11      k          NULL       NULL
    12      l          NULL       NULL
    */
      

  3.   

    hellowork(一两清风) 
    谢谢你了,
    我给你发csdn消息了,你看一下。
      

  4.   

    hellowork(一两清风) ,我看了一下,真没想到用存储过程也能写出这么强的东西。
    不过可能还有个问题,就是在删除b的时候,就不大对了。
                a
          b           c
      d      e      f   g
    h   i  j   k           l下面是删除B后A的左树的样子
                 a
          d          
      h      i         
                e
              j   k
    你的语句把h,i给弄没了,原来B的右子树E应该放在现在D的右子树的最右下,即i的右下。
    麻烦你再帮我想一下,十分感谢
      

  5.   

    一种方法用临时表存该NODE下的所有NODE,关联删除
    二:递归触发器,最多32层的限制
      

  6.   

    楼主的规则说的并不是很全面,例如下面二种情况:
    1.如果i下面还有子节点,那么删除b时,e节点该放到哪个节点下面(i还是n)
                a
          b           c
      d      e      f   g
    h   i  j   k           l
      m   n
    2.如果d节点缺少左节点,那么删除b时,e节点怎么处理?
                a
          b           c
      d      e      f   g
        i  j   k           l
      

  7.   

    楼主的规则说的并不是很全面,例如下面二种情况:
    1.如果i下面还有子节点,那么删除b时,e节点该放到哪个节点下面(i还是n)
                a
          b           c
      d      e      f   g
    h   i  j   k           l
      m   n
    2.如果d节点缺少左节点,那么删除b时,e节点怎么处理?
                a
          b           c
      d      e      f   g
        i  j   k           l
    解释第一个问题:
    1:如果i下面还有子节点,那么删除b时,e节点该放到哪个节点下面(i还是n)
    答:e节点该放到n下面
    2:如果d节点缺少左节点,那么删除b时,e节点怎么处理?
    答:删除b时,E只要朝D的最右下位置放就可以了,不要操作D的左子树,D的左子树原来是什么样,现在还是什么样
      
      

  8.   

    drop table Users
    GOcreate table Users 
    (UserID integer,
     UserName varchar(20),
      LeftNode varchar(20),
      RightNode varchar(20)
    )
    goINSERT INTO [Users]
    ([UserID], [UserName], [LeftNode], [RightNode])
    select 1, 'a', 'b', 'c'
    union all
    select 2, 'b', 'd', 'e'
    union all
    select 3, 'c', 'f', 'g'
    union all
    select 4, 'd', 'h','i'
    union all
    select 5, 'e', 'j', 'k'
    union all
    select 6, 'f', null, null
    union all
    select 7, 'g', null, 'l'
    union all
    select 8, 'h', null, null
    union all
    select 9, 'i', null, null
    union all
    select 10, 'j', null, null
    union all
    select 11, 'k', null, null
    union all
    select 12, 'l', null, null
    goselect * from Users----创建存储过程
    --取尾巴节点
    CREATE FUNCTION pGetLastNode(@UserName varchar(20))
        RETURNS varchar(20)
    as
    BEGIN
        DECLARE @NODE varchar(20)
        DECLARE @Pre_NODE varchar(20)
        SELECT @NODE=@UserName,@Pre_NODE=@UserName
        
        WHILE @NODE IS NOT NULL
        BEGIN
            SELECT @Pre_NODE=@NODE
            SELECT @NODE=RightNode FROM Users WHERE UserName=@NODE
        END
        RETURN @Pre_NODE
    ENDSELECT dbo.pGetLastNode('b')
    --DROP PROC pDeleteNode
    create proc pDeleteNode @UserName varchar(20)
    as
    begin
        DECLARE @LeftNode varchar(20)
        DECLARE @RightNode varchar(20)
        DECLARE @ParentNode varchar(20)
        DECLARE @LastNode varchar(20)
        DECLARE @NodeType int    SELECT @ParentNode='',@NodeType=0    SELECT @ParentNode=UserName,@NodeType=1 FROM Users WHERE LeftNode=@UserName    SELECT @ParentNode=UserName,@NodeType=2 FROM Users WHERE RightNode=@UserName    SELECT @LeftNode=LeftNode,@RightNode=RightNode FROM Users
            WHERE UserName=@UserName    IF @LeftNode IS NOT NULL
        BEGIN
            SELECT @LastNode=dbo.pGetLastNode(@LeftNode)        IF @NodeType=1
                UPDATE Users SET LeftNode=@LeftNode
                    WHERE UserName=@ParentNode
            ELSE
                UPDATE Users SET RightNode=@LeftNode
                    WHERE UserName=@ParentNode        UPDATE Users SET RightNode=@RightNode
                WHERE UserName=@LastNode
        END
        ELSE
        BEGIN
            IF @NodeType=1
                UPDATE Users SET LeftNode=@RightNode
                    WHERE UserName=@ParentNode
            ELSE
                UPDATE Users SET RightNode=@RightNode
                    WHERE UserName=@ParentNode
        END    DELETE Users WHERE UserName=@UserName
    end
    GO
    ----测试
    exec pDeleteNode 'h'
    exec pDeleteNode 'e'
    exec pDeleteNode 'g'
    ----查看
    select * from Users----清除测试环境
    --drop table Users
    --drop proc pDeleteNode