Как я могу написать процедуру, чтобы найти набор строк, как это? - PullRequest
1 голос
/ 19 октября 2010

Извините за заголовок мусорного вопроса. У меня есть таблица 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 путем пересечения с последовательными наборами ключей, которые содержат другие элементы

Ответы [ 3 ]

2 голосов
/ 19 октября 2010

Вы можете использовать полное внешнее объединение между каждым набором и набором чисел, чтобы увидеть, совпадают ли они.Эта функция делает это:

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.

Я не реализовал часть о создании нового набора, если ничего не найдено, но это должнобыть достаточно легкимЛично мне не нравятся функции с побочными эффектами (в данном случае вставка строк в таблицу).

0 голосов
/ 19 октября 2010

Oracle 11g представила функцию LISTAGG, которую можно использовать для того, что вам нужно.Возьмите в качестве примера приведенный ниже пример, поскольку я не очень знаком с оракулом, но он должен работать, возможно, с некоторыми незначительными исправлениями):

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); 
0 голосов
/ 19 октября 2010

Быстрый способ найти пересечение может состоять в том, чтобы создать глобальную временную таблицу и заполнить ее переданной таблицей чисел.Затем вы можете присоединиться к этой таблице с помощью 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)

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...