0

I have a table that supposed to be searched with multiple columns, which can have multiple values

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

It looks fine to me as it does index lookup on more selective column. But I also have a requirement to search for all values if argument is not passed and I am really stuck with that.

The main question I think is how to write sql to search a table by multiple columns with multiple possible values in these columns? I want to be able to take advantage of bitmap indexes.

Should I maybe stick to Dynamic SQL for such task?

UPDATE. That is how I currently solved it for the moment.

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;
Slava Lenskyy
  • 426
  • 2
  • 10
  • To clarify, your problem is that `strarray` parameter, for example, `a`, may be empty? And in this scenario, you would like the `object_name` not to be taken into consideration in the `WHERE` clause (i. e. all possible values of `object_name` should be taken into account)? – Przemyslaw Kruglej Oct 29 '13 at 21:34
  • Perhaps you just need to modify the predicates, such as adding `or (select count(*) from table(a)) = 0`. – Jon Heller Oct 30 '13 at 05:38
  • @Przemyslaw Kruglej, yes you are right. – Slava Lenskyy Oct 30 '13 at 06:13
  • So your current solution works as you expect it? I do not see any possibility to make it shorter/easier other than (if you'll have more than 2 array parameters) creating a nested function to return a string condition so that you don't have to write a separate one for each array paremeter, but other than that I can't think of any improvement. Maybe someone else will come up with something. – Przemyslaw Kruglej Oct 30 '13 at 08:01

0 Answers0