Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 Recursive Triggers

Author  Topic 

bartman_z
Starting Member

11 Posts

Posted - 2005-12-16 : 08:38:46
Hi there,

I have a table with the following type of data

MasterID ---- RelatedRecordID
1 -------------- NULL
2 --------------- 1
3 --------------- 1
4 --------------- 2
5 --------------- 2
6 --------------- 4

etc etc you get the general idea.

I want to be able to delete the record with MasterID 1 and a trigger or something to automatically 'cascade' down all the related records and delete them.

I have tried (unsuccessfully) to create relationships with cascade deletes and to create a trigger but all to no avail.

Any help or pointers in the right direction would be much appreciated.

Bartman


www.meridiantd.co.uk

TG
Master Smack Fu Yak Hacker

6065 Posts

Posted - 2005-12-16 : 11:25:08
Yeah, sql doesn't like cascade deletes for hierarchal relationships. You can cascade throught the whole table. You can get around it using an INSTEAD of trigger but I wouldn't.

I would urge you not to use this approach, its too easy to wipe out all your data.

set nocount on

create table junk
(masterid int primary key
,rid int references junk (masterid) /*on delete cascade*/)
--sql doesn't like a delete cascade for hierarchal relationship
go
--so need to use an instead of trigger
create trigger tr_junk_del on junk instead of delete
as
begin
set nocount on
declare @tb table (masterid int)

insert @tb (masterid)
select masterid from deleted

insert @tb (masterid)
select j.masterid
from deleted d
join junk j
on j.rid = d.masterid
group by j.masterid


while @@rowcount > 0
begin
insert @tb (masterid)
select j.masterid
from @tb d
join junk j
on j.rid = d.masterid
left join @tb ex
on ex.masterid = j.masterid
where ex.masterid is null
group by j.masterid
end

delete j
from junk j
join @tb t on t.masterid = j.masterid
end
go

insert junk values (1,null)
insert junk values (2,1)
insert junk values (3,2)
insert junk values (4,3)
insert junk values (5,4)
insert junk values (6,5)
go

print 'junk before delete:'
select * from junk

set nocount off
print 'perform delete'
delete junk where masterid = 1

set nocount on
print 'shows 1 row affected but really wiped out whole table'

print 'junk after delete:'
select * from Junk

go
drop table junk


Be One with the Optimizer
TG
Go to Top of Page

blindman
Master Smack Fu Yak Hacker

2365 Posts

Posted - 2005-12-16 : 12:59:03
A case could be made that this logic is complex enough that it would be better suited to a stored procedure than a trigger (you ARE preventing users from directly accessing tables, right?), but here is a method you can use either way:

In your trigger or sproc, create a temporary table for holding ID values of records to be deleted.
Seed it with the ID of the record being deleted.
Append child records of all IDs in your temporary table that are not already in the table, and loop until no new IDs are added.
Perform a single DELETE against your production table to remove all records corresponding IDs in your temporary table.
Go to Top of Page

TG
Master Smack Fu Yak Hacker

6065 Posts

Posted - 2005-12-16 : 13:24:09
quote:
In your trigger or sproc, create a temporary table for holding ID values of records to be deleted.
Seed it with the ID of the record being deleted.
Append child records of all IDs in your temporary table that are not already in the table, and loop until no new IDs are added.
Perform a single DELETE against your production table to remove all records corresponding IDs in your temporary table.

I like your logic. Maybe because it's identical to what I used in my post . Is that why they call you blindman?

Be One with the Optimizer
TG
Go to Top of Page

blindman
Master Smack Fu Yak Hacker

2365 Posts

Posted - 2005-12-16 : 14:48:12
I don't see your point.
Ha ha
Actually, I stopped reading your post at "INSTEAD OF", because I don't implement it this way and so assumed that your entire solution was different. My bad.
Go to Top of Page

TG
Master Smack Fu Yak Hacker

6065 Posts

Posted - 2005-12-16 : 15:26:27
No bad. It just validated the choice of logic. It's funny to me because it really is identical (line by line)

The only reason I chose "instead of" trigger is because I thought if he wanted to put the constraint on there, then a normal "after" trigger may never fire if the delete violated the constraint. I don't know if that's true or not but that was the reason...

Anyway keep up the good work!



Be One with the Optimizer
TG
Go to Top of Page

cmschick
Starting Member

20 Posts

Posted - 2005-12-30 : 22:41:37
quote:
quote:
--------------------------------------------------------------------------------
In your trigger or sproc, create a temporary table for holding ID values of records to be deleted.
Seed it with the ID of the record being deleted.
Append child records of all IDs in your temporary table that are not already in the table, and loop until no new IDs are added.
Perform a single DELETE against your production table to remove all records corresponding IDs in your temporary table.
--------------------------------------------------------------------------------


I like your logic. Maybe because it's identical to what I used in my post . Is that why they call you blindman?

Be One with the Optimizer
TG




Hi TG,

I'm hoping you are subscribed to this post. Can you spell out exactly how to do this? I don't know what you mean when you say "Seed it with the ID of the record being deleted" The same goes for "Append child records of all IDs in your temporary table that are not already in the table, and loop until no new IDs are added."

Thank you.

Christopher Schick


The Schickster
Go to Top of Page

TG
Master Smack Fu Yak Hacker

6065 Posts

Posted - 2005-12-31 : 09:39:39
Hey Chris,
The verbal description (quoted) is from blindman, but it is exactly the technique I used in my 1st post on this thread.

>>Seed it with the ID of the record being deleted

insert @tb (masterid)
select masterid from deleted


>>Append child records of all IDs in your temporary table that are not already in the table

insert @tb (masterid)
select j.masterid
from deleted d
join junk j
on j.rid = d.masterid
group by j.masterid


>>and loop until no new IDs are added

while @@rowcount > 0
begin
insert @tb (masterid)
select j.masterid
from @tb d
join junk j
on j.rid = d.masterid
--this section just insures the added IDs don't already exist in the table
left join @tb ex
on ex.masterid = j.masterid
where ex.masterid is null

group by j.masterid
end


Finally, delete all affected rows from the real table (including the row that the user inteneded to delete - the row we first seeded - since this is an INSTEAD of trigger)

delete j
from junk j
join @tb t on t.masterid = j.masterid


Be One with the Optimizer
TG
Go to Top of Page

cmschick
Starting Member

20 Posts

Posted - 2005-12-31 : 10:54:34
Thanks TG,

You're a big help.

Chris

The Schickster
Go to Top of Page
   

- Advertisement -