如何写这样的触发器?(先序遍历树算法原理)

conannb 2008-02-02 11:36:06
CREATE TABLE nested_category (
category_id INT IDENTITY (1,1) PRIMARY KEY,
name VARCHAR(20) NOT NULL,
parent_id INT NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
);
INSERT INTO nested_category VALUES (1,'ELECTRONICS',1,1,20);
INSERT INTO nested_category VALUES (2,'TELEVISIONS',1,2,9);
INSERT INTO nested_category VALUES (3,'TUBE',2,3,4);
INSERT INTO nested_category VALUES (4,'LCD',2,5,6);
INSERT INTO nested_category VALUES (5,'PLASMA',2,7,8);
INSERT INTO nested_category VALUES (6,'PORTABLE ELECTRONICS',1,10,19);
INSERT INTO nested_category VALUES (7,'MP3 PLAYERS',10,11,14);
INSERT INTO nested_category VALUES (8,'FLASH',11,12,13);
INSERT INTO nested_category VALUES (9,'CD PLAYERS',10,15,16);
INSERT INTO nested_category VALUES (10,'2 WAY RADIOS',10,17,18);

现想执行插入、删除结点操作,如何根据插入删除结点的parent_id字段,自动更新其他结点想对应的lft,rgt字段?
这样的触发如何写?
谢谢

...全文
322 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
xierfly 2008-02-02
  • 打赏
  • 举报
回复
=====给你提供一个 级联更新的触发器,应该对你有所帮助的。

假如: 创建两张表 testtable1 , test
表一:
testtable1
(id int identity(1,1) primary key not null,
tst nvarchar(100) not null

插入两条测试记录:
insert into testtable1 values('test1')
insert into testtable1 values('test2')
表二:
test
(
id int itdentity(1,1) primary key not null,
title nvarchar(100) not null
)
插入两条测试记录:
insert into test values('title1')
insert into test values('title2')

创建触发器: 目的是在更改testtable1中的某一条记录时,test对应的记录也要随着更改。从而实现级联更新的效果。

create trigger triChange
on testtable1
// 触发器要创建在动作发出方。也就是说,当testatble1表中的记录 发生变化时,才引起test表随着改变
for update
as
begin
update test
set title = testtable1.tst
from test inner join testtable1 on _disibledevent= testtable1.id
where test.id in (select id from inserted)//这里要注意inserted表,其实它是个虚拟表,只是记录了对testtable1的操作。 其中where条件也可以更改为where test.id = (select id from inserted).因为每执行一次,都会触发这个触发器,所以,id每次只有一个。不过,安全其间,最好用"in"。
end

中国风 2008-02-02
  • 打赏
  • 举报
回复
用触发器递归可以实现。。
或用
循环
utpcb 2008-02-02
  • 打赏
  • 举报
回复
up
wzy_love_sly 2008-02-02
  • 打赏
  • 举报
回复
不好弄 先占个位置等
-狙击手- 2008-02-02
  • 打赏
  • 举报
回复
有分不
conannb 2008-02-02
  • 打赏
  • 举报
回复
谢谢 结贴:)
昵称被占用了 2008-02-02
  • 打赏
  • 举报
回复
--可以合成一个触发器
--并增加处理一条记录的检测

create trigger tr_nested_category
on nested_category
for insert,update,delete
as

set nocount on
--修改其他字段退出
if exists (select 1 from deleted)
and exists (select 1 from inserted)
and (not update(parent_id))
return

if (select count(1) from deleted)>1 or (select count(1) from inserted)>1
begin
RAISERROR ('一次只能处理一条记录.', 16, 1)
ROLLBACK TRANSACTION
return
end

declare @lft int
declare @rgt int
declare @id int

--删除操作
select @lft=lft,@rgt=rgt,@id=category_id from deleted

update nested_category
set lft=lft-1
where lft>=@rgt

update nested_category
set rgt=rgt-1
where rgt>=@rgt


update nested_category
set lft=lft-1
where lft>=@lft

update nested_category
set rgt=rgt-1
where rgt>=@lft

--插入操作
select @rgt=p.rgt,@id=i.category_id from nested_category p,inserted i
where i.parent_id=p.category_id

update nested_category
set lft=lft+2
where lft>=@rgt

update nested_category
set rgt=rgt+2
where rgt>=@rgt

update nested_category
set lft=@rgt,rgt=@rgt+1
where category_id=@id

go
昵称被占用了 2008-02-02
  • 打赏
  • 举报
回复
移动应该是个更新操作,可以再写个update触发器

--注意,同样需要限定一次只能更新一条记录
--可以理解为先删除一条记录,再插入一条记录

create trigger tr_nested_category_update
on nested_category
for update
as


declare @lft int
declare @rgt int
declare @id int

if update (parent_id) ---只有更新parent_id字段时才需要触发
begin
--删除操作
select @lft=lft,@rgt=rgt,@id=category_id from deleted

update nested_category
set lft=lft-1
where lft>=@rgt

update nested_category
set rgt=rgt-1
where rgt>=@rgt


update nested_category
set lft=lft-1
where lft>=@lft

update nested_category
set rgt=rgt-1
where rgt>=@lft

--插入操作
select @rgt=p.rgt,@id=i.category_id from nested_category p,inserted i
where i.parent_id=p.category_id

update nested_category
set lft=lft+2
where lft>=@rgt

update nested_category
set rgt=rgt+2
where rgt>=@rgt

update nested_category
set lft=@rgt,rgt=@rgt+1
where category_id=@id
end
go

昵称被占用了 2008-02-02
  • 打赏
  • 举报
回复
是笔误,可以简化为
select @lft=lft,@rgt=rgt,@id=category_id from deleted


conannb 2008-02-02
  • 打赏
  • 举报
回复
谢谢,刚才测试了下,改正了你的笔误后,可以通过。另外,如果要是移动节点,(例如,本来是A节点下的一个叶子节点B 现移动到C节点下,A/C同层,)可以写吗?
conannb 2008-02-02
  • 打赏
  • 举报
回复
关于delete的时候是不是笔误?
select @lft=lft,@rgt=rgt,@id=i.category_id from inserted
select @lft=lft,@rgt=rgt,@id=d.category_id from deleted d
??

昵称被占用了 2008-02-02
  • 打赏
  • 举报
回复
--删除触发器
--同样只能一次删除一条记录
--而且不能删除非叶子节点

create trigger tr_nested_category_delete
on nested_category
for delete
as

declare @lft int
declare @rgt int
declare @id int
select @lft=lft,@rgt=rgt,@id=i.category_id from inserted

update nested_category
set lft=lft-1
where lft>=@rgt

update nested_category
set rgt=rgt-1
where rgt>=@rgt


update nested_category
set lft=lft-1
where lft>=@lft

update nested_category
set rgt=rgt-1
where rgt>=@lft


go
昵称被占用了 2008-02-02
  • 打赏
  • 举报
回复
--插入触发器
--必须限定一次只能插入一条记录,代码里没写这个限定

create trigger tr_nested_category_Insert
on nested_category
for insert
as

declare @rgt int
declare @id int
select @rgt=p.rgt,@id=i.category_id from nested_category p,inserted i
where i.parent_id=p.category_id

update nested_category
set lft=lft+2
where lft>=@rgt

update nested_category
set rgt=rgt+2
where rgt>=@rgt

update nested_category
set lft=@rgt,rgt=@rgt+1
where category_id=@id
go
conannb 2008-02-02
  • 打赏
  • 举报
回复
其实,抛开设计和效率问题,这个触发器写起来并不复杂
============================================
说的有理 ,效率可能会降低,因为要更改大部分数据
对数据库操作不是很熟悉,麻烦给写一下 顺便推荐本sql的书吧:)
昵称被占用了 2008-02-02
  • 打赏
  • 举报
回复
其实,抛开设计和效率问题,这个触发器写起来并不复杂
昵称被占用了 2008-02-02
  • 打赏
  • 举报
回复
不知道,也许先序遍历树就不应该是这个从书上抄下来的结构

至少,一个操作能引起一个表所有记录变动的话,这个应用就不应该用数据库了
conannb 2008-02-02
  • 打赏
  • 举报
回复

这样的设计相当有问题,如果依你上面的例子,我删除一个节点会引起所有记录的修改
===================================================================
怎样设计比较合理呢?
昵称被占用了 2008-02-02
  • 打赏
  • 举报
回复

这样的设计相当有问题,如果依你上面的例子,我删除一个节点会引起所有记录的修改,
所以,我想如果你坚持这个设计的话,强烈建议你不要用触发器,因为反正需要修改所有记录,你用个存储过程好了(也许你必须建议你的用户数据量的限定,每次操作的人数限制等)

conannb 2008-02-02
  • 打赏
  • 举报
回复
conannb 2008-02-02
  • 打赏
  • 举报
回复
lft,rgt是左、右兄弟节点吗,那就应该有表示节点次序的,否则插入一个节点,不知道是插在最后还是中间
====================================================================================
lft,rgt表示节点的遍历顺序
加载更多回复(2)

22,207

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧