这类似于this question,虽然有一个扭曲(即,我需要的是基本上这里的引用计数行为)。
我们有几个表(Foo,Bar,Baz),其中存储的东西都是零或更多的另一种东西(Blah)。我们有时会制作新的Blah并将它们贴在Foo,Bar或Baz上;但是,我们不会编辑现有的Blahs,因为它们可能会被多个事物同时指向。目前,我们有一个批处理过程,扫描数据库中的所有Foos,Bars和Bazes,标记Blahs,然后删除所有未标记的Blahs,但这是非常昂贵的,所以我们正在寻找一种方法它在线,理想情况下通过数据库本身。我们可以研究基于触发器的方法,但宁愿将它们视为最后的手段。
具体而言,请参考this SQLFiddle中的架构和数据:
我是否坚持使用触发器或现有的标记扫描批处理来完成这项工作,或者有更好的方法吗?
答案 0 :(得分:1)
不需要标记和扫描批处理,因为只要BLAHS.PK
永远不能包含逗号,以下查询就可以完成工作:
delete from blahs
where not exists (select 1 from foo where ','||some_blahs||',' like '%,'||blahs.pk||',%')
and not exists (select 1 from bar where bar.blah = blahs.pk)
and not exists (select 1 from baz where blahs.pk in (baz.a_blah, baz.another_blah));
您的表格FOO
很麻烦,因为您无法像BAR
和BAZ
一样定义任何参照完整性或任何有用的索引。
更好的数据库设计可能是用多对多关系表替换FOO.SOME_BLAHS
:
create table foo_blahs ( foo_pk varchar2(20) references foo on delete cascade
, blah_pk varchar2(20) references blahs
, constraint foo_blah_pk primary key (foo_pk, blah_pk) enable);
然后代替:
insert into foo (pk, some_blahs) values ('a_foo', 'a,b,c');
你会使用:
insert into foo (pk) values ('a_foo');
insert into foo_blahs (foo_pk, blah_pk) values ('a_foo', 'a');
insert into foo_blahs (foo_pk, blah_pk) values ('a_foo', 'b');
insert into foo_blahs (foo_pk, blah_pk) values ('a_foo', 'c');
,删除查询将变为:
delete from blahs
where not exists (select 1 from foo_blahs where foo_blahs.blah_pk = blahs.pk)
and not exists (select 1 from bar where bar.blah = blahs.pk)
and not exists (select 1 from baz where blahs.pk in (baz.a_blah, baz.another_blah));