Предикат Oracle Nested Table в предложении where

У меня есть таблица, в которой предполагается искать несколько столбцов, которые могут иметь несколько значений.

create table t as select * from all_objects;

create bitmap index IDX_DATA_OBJECT_ID on T (DATA_OBJECT_ID);
create bitmap index IDX_LAST_DDL_TIME on T (LAST_DDL_TIME);
create bitmap index IDX_OBJECT_NAME on T (OBJECT_NAME);
create bitmap index IDX_OBJECT_TYPE on T (OBJECT_TYPE);

create or replace type strarray as table of varchar2(4000)

CREATE OR REPLACE PROCEDURE p_search(op_cursor out SYS_REFCURSOR
                                ,a         strarray
                                ,b         strarray) IS
                                ca constant number:= a.count;
                                cb constant number:= b.count;
BEGIN
  OPEN op_cursor FOR
  SELECT /*+ gather_plan_statistics asda*/  *
    FROM t
   WHERE object_name IN (SELECT * FROM TABLE(a))
     AND object_type IN (SELECT * FROM TABLE(b));
END;

declare
  op_cursor sys_refcursor;
  c t%rowtype;
begin
  p_search(op_cursor,strarray('ICOL$'),strarray('TABLE'));
  loop
    fetch op_cursor into c;
    exit when op_cursor%notfound;
  end loop;
end;

-----------------------------------------------------------------
| Id  | Operation                             | Name            |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                 |
|*  1 |  HASH JOIN SEMI                       |                 |
|   2 |   NESTED LOOPS                        |                 |
|   3 |    NESTED LOOPS                       |                 |
|   4 |     SORT UNIQUE                       |                 |
|   5 |      COLLECTION ITERATOR PICKLER FETCH|                 |
|   6 |     BITMAP CONVERSION TO ROWIDS       |                 |
|*  7 |      BITMAP INDEX SINGLE VALUE        | IDX_OBJECT_NAME |
|   8 |    TABLE ACCESS BY INDEX ROWID        | T               |
|   9 |   COLLECTION ITERATOR PICKLER FETCH   |                 |
-----------------------------------------------------------------

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

Главный вопрос, который я думаю, заключается в том, как написать sql для поиска таблицы по нескольким столбцам с несколькими возможными значениями в этих столбцах? Я хочу иметь возможность использовать растровые индексы.

Должен ли я придерживаться динамического SQL для такой задачи?

ОБНОВИТЬ. Вот как я сейчас решил это на данный момент.

create context my_ctx using p_search;

CREATE OR REPLACE FUNCTION in_list(p_string IN VARCHAR2) RETURN strarray AS
   l_string LONG DEFAULT p_string || ',';
   l_data   strarray := strarray();
   n        NUMBER;
BEGIN
   LOOP
      EXIT WHEN l_string IS NULL;
      n := instr(l_string, ',');
      l_data.extend;
      l_data(l_data.count) := ltrim(rtrim(substr(l_string, 1, n - 1)));
      l_string := substr(l_string, n + 1);
   END LOOP;

   RETURN l_data;
END;

CREATE OR REPLACE PROCEDURE p_search(op_cursor OUT SYS_REFCURSOR
                                    ,a         VARCHAR2
                                    ,b         VARCHAR2) IS
   l VARCHAR2(4000);
BEGIN
   l := 'SELECT /*+ gather_plan_statistics lvv3*/
       *
        FROM t
       WHERE 1=1';

   IF a IS NOT NULL
   THEN
      dbms_session.set_context('MY_CTX', 'OBJ_NAME', a);
      l := l || ' and t.object_name in (select /*+ cardinality (objn 5)*/ * from table(cast(in_list(sys_context( ''MY_CTX'',''OBJ_NAME'' )) as strarray)
                                             ) objn
                         )';
   END IF;

   IF b IS NOT NULL
   THEN
      dbms_session.set_context('MY_CTX', 'OBJ_TYPE', b);
      l := l || ' and t.object_type in (select /*+ cardinality (objt 5)*/ * from table(cast(in_list(sys_context( ''MY_CTX'',''OBJ_TYPE'' )) as strarray)
                                             ) objt
                         )';
   END IF;

   OPEN op_cursor FOR l;
   dbms_session.clear_context('MY_CTX');
END;

person Slava Lenskyy    schedule 29.10.2013    source источник
comment
Чтобы уточнить, ваша проблема в том, что параметр strarray, например, a, может быть пустым? И в этом случае вы хотите, чтобы object_name не учитывалось в предложении WHERE (т. е. учитывались все возможные значения object_name)?   -  person Przemyslaw Kruglej    schedule 30.10.2013
comment
Возможно, вам просто нужно изменить предикаты, например добавить or (select count(*) from table(a)) = 0.   -  person Jon Heller    schedule 30.10.2013
comment
@Przemyslaw Kruglej, да, ты прав.   -  person Slava Lenskyy    schedule 30.10.2013
comment
Итак, ваше текущее решение работает так, как вы ожидаете? Я не вижу никакой возможности сделать его короче/проще, кроме как (если у вас будет более 2 параметров массива) создания вложенной функции для возврата строкового условия, чтобы вам не приходилось писать отдельный для каждого массива paremeter, но кроме этого я не могу придумать никакого улучшения. Может еще кто что придумает.   -  person Przemyslaw Kruglej    schedule 30.10.2013