我如何编写一个过程来查找这样的一组行?

发布于 2024-09-28 17:08:20 字数 585 浏览 4 评论 0原文

抱歉问题标题很垃圾。我有一个像这样的表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 中执行此操作的好方法是什么?

编辑:我目前正在研究的解决方案是这样的(我不确定它是否会起作用):

  1. 选择将第一个元素放入某个集合 c 中的所有键,
  2. 通过以下方式细化集合 c与包含其他元素的连续键集相交

Sorry about the rubbish question title. I have a table SET_DEFINITIONS like this:

SETKEY      NOT NULL    NUMBER(38)
SETENTRY    NOT NULL    NUMBER(38)

where the idea is that the rows define sets of numbers. For example the table could contain rows:

1 2
1 4
2 1
2 2

which would mean set 1 is {2,4} and set 2 is {1,2}. I want to write a function

function selectOrInsertSet(table of number(38) numbers) return number(38)

which will return the key of a set with the same members as the passed in table (or create such a set if it doesn't exist). What's a good way to do this in PL/SQL?

EDIT: the solution I'm currently working on goes like this (and I'm not sure it'll work):

  1. select all keys that have the first element into some collection c
  2. refine the collection c by intersecting with successive sets of keys that contain the other elements

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

来日方长 2024-10-05 17:08:21

找到交集的一种快速方法可能是创建一个全局临时表并用传入的数字表填充它。然后,您可以使用 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)

希望这会有所帮助。

A quick way to find the intersection may be to create a global temporary table and populate it with the passed in table of numbers. You could then join this table with SET_DEFINITIONS to find all possible matches. You would need to do a check on the total number in each matched set to eliminate supersets.

Create some base tables...

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 a global temporary table to hold the passed on values:

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);

Join with set_definitions to find the matching set(s):

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)

Hope this helps.

沐歌 2024-10-05 17:08:21

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); 

Oracle 11g introduced LISTAGG function that ciould be used for what you need.
Take example below as idea, as I'm not really familiar with oracle, but it should work with probably some minor corrections):

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); 
谁与争疯 2024-10-05 17:08:20

您可以在每个集合和数字集合之间使用完整的外连接来查看它们是否相同。该函数执行以下操作:

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。

我还没有实现关于创建新集合(如果没有找到)的部分,但这应该很容易。我个人不喜欢有副作用的函数(在本例中,将行插入表中)。

You can use a full outer join between each set and the collection of numbers to see if they are the same. This function does that:

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;

This returns the setkey if found, else null.

I haven't implemented the part about creating a new set if none is found, but that should be easy enough. I don't personally like functions that have side effects (in this case, inserting rows into a table).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文