0

I have a table (let's call it tMainTable) which is currently referred by many other table (and their number might just grow over time).

Several of those tables cannot just have the ON DELETE CASCADE clause due to cycling detection.

I know I could remove the ON DELETE CASCADE clause if I write an INSTEAD OF trigger on tMainTable.

But then whenever a new table is added as descendant of tMainTable one would have to edit the trigger which (as a "modularity" addict) is just lame (and risky - imagine an unexperienced user just breaks the whole thing).

So I'm seriously looking for an alternative way to proceed.

And I just have something in my mind.

What if I create a table tMainTableID which just hold a copy of every ID of tMainTable (copy made with AFTER trigger for insertion)?

Then, I create an INSTEAD OF trigger on tMainTable which first delete the corresponding row of tMainTableID, then delete the actual rows of tMainTable.

If I do that, I should have something really nice to work with: a table (tMainTableID) which I can "attach" AFTER DELETE triggers on to delete anything that needs to be deleted before rows of tMainTable get actually deleted.

-- Made by ME on 2014-01-27
CREATE TRIGGER tMainTableID_AFDEL_tTableChild01
AFTER DELETE
ON tMainTableID
AS
BEGIN
    DELETE T
    FROM deleted AS D
    INNER JOIN tTableChild01 AS T ON (
        T.RefToMainID = D.ID
    )
END
GO

-- Made by ME on 2015-01-01
CREATE TRIGGER tMainTableID_AFDEL_tTableChild02
AFTER DELETE
ON tMainTableID
AS
BEGIN
    DELETE T
    FROM deleted AS D
    INNER JOIN tTableChild02 AS T ON (
        T.RefToMainID = D.ID
    )
END
GO

-- Made by Iamun Kompetent on 2016-01-01
CREATE TRIGGER tMainTableID_AFDEL_tTableChild03
AFTER DELETE
ON tMainTableID
AS
BEGIN
    DELETE T
    FROM inserted AS D
    INNER JOIN tTableChild02 AS T ON (
        D.ID = D.ID
    )
END
GO  

Do you see anything wrong with this approach or even better, do you know a better way to attain modularity?

-- EDIT: Simple example

create table tTest20140128 (
    id int not null primary key
)
go

create table tTest20140128_Child01 (
    id int not null primary key references tTest20140128(id) on delete no action
)
go

create table tTest20140128_Child02 (
    id int not null primary key references tTest20140128(id) on delete no action
)
go

insert tTest20140128 values (1), (2), (3)
insert tTest20140128_Child01 values (1), (2), (3)
insert tTest20140128_Child02 values (1), (2), (3)
go

delete from tTest20140128 -- Error
go

-- table for holding copies of ids
create table tTest20140128_ID (
    id int not null primary key references tTest20140128(id) on delete no action
)
go

insert tTest20140128_ID
select id from tTest20140128
go

-- trigger that keeps tTest20140128_ID up to date for new ids
create trigger tTest20140128_AFINS
on tTest20140128
after insert
as
begin
    insert tTest20140128_ID
    select id from inserted
end
go

-- Instead of delete (keeps tTest20140128_ID up to date for deleted ids)
create trigger tTest20140128_IODEL
on tTest20140128
instead of delete
as
begin
    delete ID
    from deleted AS D
    inner join tTest20140128_ID AS ID ON (
        ID.id = D.id
    )

    delete from T
    from deleted AS D
    inner join tTest20140128 AS T on (
        T.id = D.id
    )
end
go

-- Sorta "attching listeners to event" 
-- tTest20140128_Child01
create trigger tTest20140128_tTest20140128_Child01
on tTest20140128_ID
after delete
as
begin
    delete T
    from deleted as D
    inner join tTest20140128_Child01 AS T on (
        T.id = D.id
    )
end
go

-- tTest20140128_Child02
create trigger tTest20140128_tTest20140128_Child02
on tTest20140128_ID
after delete
as
begin
    delete T
    from deleted as D
    inner join tTest20140128_Child02 AS T on (
        T.id = D.id
    )
end
go

-- New tests
insert tTest20140128 values (4), (5), (6)
insert tTest20140128_Child01 values (4), (5), (6)
insert tTest20140128_Child02 values (4), (5), (6)
go

select COUNT (*) as [COUNT after insert] from tTest20140128
go

delete from tTest20140128 -- No Error
go

select COUNT (*) as [COUNT" after delete] from tTest20140128
go

drop table tTest20140128_ID
drop table tTest20140128_Child02
drop table tTest20140128_Child01
drop table tTest20140128
Serge
  • 6,554
  • 5
  • 30
  • 56
  • Why not just make the `INSTEAD OF` trigger on tMainTable first "delete anything that needs to be deleted before rows of tMainTable", and "then delete the actual rows of tMainTable"? – Doug_Ivison Jan 27 '14 at 20:29

1 Answers1

0

The table creation sounds unnecessary... but your INSTEAD OF trigger sounds like a great idea:

How about making an INSTEAD OF trigger on tMainTable, that will first "delete anything that needs to be deleted before rows of tMainTable", and then "delete the actual rows of tMainTable"?

Doug_Ivison
  • 778
  • 7
  • 17