对于垃圾问题标题感到抱歉。我有一张SET_DEFINITIONS
这样的表:
SETKEY NOT NULL NUMBER(38)
SETENTRY NOT NULL NUMBER(38)
其中的想法是行定义了数字集。例如,该表可以包含行:
1 2
1 4
2 1
2 2
这意味着集合1是{2,4},集合2是{1,2}。我想写一个函数
function selectOrInsertSet(table of number(38) numbers) return number(38)
将返回一个集合的密钥,该集合的密钥与传入的表中的成员相同(或者如果它不存在则创建这样的集合)。在PL / SQL中执行此操作的好方法是什么?
编辑:我目前正在处理的解决方案是这样的(我不确定它是否可行):
答案 0 :(得分:2)
您可以在每个集合和数字集合之间使用完全外部联接,以查看它们是否相同。这个功能可以做到:
function selectOrInsertSet(numbers number_tt) return number
is
l_diff number;
l_retval number;
begin
for r in (select distinct setkey from set_definitions)
loop
with d as (select column_value from table(numbers)),
s as (select setentry from set_definitions where setkey=r.setkey)
select count(*)
into l_diff
from s
full outer join d on d.column_value = s.setentry
where s.setentry is null or d.column_value is null;
if l_diff = 0 then
l_retval := r.setkey;
exit;
end if;
end loop;
return l_retval;
end;
如果找到则返回setkey,否则返回null。
如果没有找到,我还没有实现关于创建新集的部分,但这应该很容易。我个人并不喜欢有副作用的函数(在这种情况下,将行插入表中)。
答案 1 :(得分:0)
查找交集的快速方法可能是创建一个全局临时表,并使用传入的数字表填充它。然后,您可以使用SET_DEFINITIONS连接此表以查找所有可能的匹配项。您需要检查每个匹配集中的总数以消除超集。
创建一些基表......
create table set_definitions (
setkey number,
setentry number,
constraint pk_set_definitions primary key (setkey, setentry)
);
insert into set_definitions values (1,2);
insert into set_definitions values (1,4);
insert into set_definitions values (2,1);
insert into set_definitions values (2,2);
insert into set_definitions values (3,1);
insert into set_definitions values (3,2);
insert into set_definitions values (3,3);
创建一个全局临时表来保存传递的值:
create global temporary table tmp_setentry (
setentry number,
constraint pk_tmp_setentry primary key (setentry));
insert into tmp_setentry values (1);
insert into tmp_setentry values (2);
加入set_definitions以查找匹配的集合:
select
setkey
from
(
select
setkey,
count(*) num_matches,
(select count(*) from set_definitions where setkey = s.setkey)
num_set_entries,
(select count(*) from tmp_setentry) num_entries
from
set_definitions s
inner join tmp_setentry t on t.setentry = s.setentry
group by
setkey
)
where
num_matches = num_entries
and num_set_entries = num_entries
--> 2 (3 is dropped as a superset)
希望这有帮助。
答案 2 :(得分:0)
Oracle 11g引入了LISTAGG功能,可以用于您需要的功能。 以下面的例子作为想法,因为我对oracle并不熟悉,但它可能适用于一些小的修正):
Create table set_definitions (setkey int, setentry int);
Create table searchFor (setentry int);
insert into set_definitions values (1,4);
insert into set_definitions values (2,1);
insert into set_definitions values (2,2);
insert into set_definitions values (3,1);
insert into set_definitions values (3,2);
insert into set_definitions values (3,3);
Insert Into searchFor Values (1);
Insert into searchFor Values (2);
With Prepare as
(
Select setkey, LISTAGG(setentry, ',') WITHIN GROUP (ORDER BY setentry) as EntryList
From set_definitions
Group by setkey
Having Count(*)=(Select Count(*) From searchFor) -- Just to eliminate obvious ones
)
Select setkey
from Prepare
Where EntryList = (Select LISTAGG(setentry, ',') WITHIN GROUP (ORDER BY setentry) From searchFor);