Использование коллекций Oracle в динамическом SQL - PullRequest
1 голос
/ 25 августа 2010

Мне нужно проверить, являются ли параметры процедуры нулевыми, а если нет, использовать их в предложении WHERE.Например:

sqlquery := 'SELECT * FROM table WHERE a_col = a AND';
IF b IS NOT NULL THEN
  sqlquery := sqlquery || ' b_col = :b';
END IF;
IF c IS NOT NULL THEN
  sqlquery := sqlquery || ' c_col = :c';
END IF;

И т. Д.

Затем мне нужно использовать оператор OPEN-FOR-USING, чтобы открыть курсор для сформированного sqlquery, но предварительно я должен решить, какие значения отправлятьс помощью пункта USINGЕдинственный способ, который я вижу, - это использовать много предложений IF:

IF b IS NOT NULL AND c IS NOT NULL THEN
  OPEN cur FOR sqlquery USING b, c;
ELSIF b IS NOT NULL THEN
  OPEN cur FOR sqlquery USING b;
ELSIF c IS NOT NULL THEN
  OPEN cur FOR sqlquery USING c;
ELSE 
  OPEN cur FOR sqlquery;

Для N значений я получаю большое количество предложений IF.Как я могу решить эту проблему без большого количества IF?Я думаю, что можно использовать Oracle Collections, но я не нашел ни одного примера.

Ответы [ 4 ]

2 голосов
/ 25 августа 2010

Вам нужно построить запрос так, чтобы он всегда ссылался на: b и: c примерно так:

sqlquery := 'SELECT * FROM table WHERE a_col = a';
IF b IS NOT NULL THEN
  sqlquery := sqlquery || ' AND b_col = :b';
ELSE 
  sqlquery := sqlquery || ' AND :b IS NULL';
END IF;
IF c IS NOT NULL THEN
  sqlquery := sqlquery || ' AND c_col = :c';
ELSE 
  sqlquery := sqlquery || ' AND :c IS NULL';
END IF;

Тогда вы можете использовать его так:

OPEN cur FOR sqlquery USING b, c;

На самом делеЯ думаю, что было бы более эффективно сделать это:

sqlquery := 'SELECT * FROM table WHERE a_col = a';
IF b IS NOT NULL THEN
  sqlquery := sqlquery || ' AND b_col = :b';
ELSE 
  sqlquery := sqlquery || ' AND (1=1 OR :b IS NULL)';
END IF;
IF c IS NOT NULL THEN
  sqlquery := sqlquery || ' AND c_col = :c';
ELSE 
  sqlquery := sqlquery || ' AND (1=1 OR :c IS NULL)';
END IF;

... потому что тогда оптимизатор может признать, что 1 = 1 всегда верно, и поэтому может полностью исключить этот предикат из рассмотрения.Я помню, что читал это где-то (статья Тома Кайта в Oracle Mag, я думаю), но сейчас не могу найти ссылку.

0 голосов
/ 26 августа 2010

У меня была похожая ситуация.

Я выяснил, какие планы выполнения работоспособны, и использовал для них отдельные запросы.

Например, скажите, что я ищу людей, а параметры: first_name, last_name. пол, дата рождения Таблица имеет индексы для (фамилия, имя, отчество) и (дата_ рождения).

IF :p_firstname IS NOT NULL and :p_lastname IS NOT NULL THEN
  OPEN cur FOR 
    'SELECT * FROM PEOPLE WHERE last_name=:a AND first_name=:b AND
     (date_of_birth = :c or :c is NULL) AND (gender = :d or :d IS NULL)' USING ....
ELSIF :p_lastname IS NOT NULL THEN
  OPEN cur FOR 
    'SELECT * FROM PEOPLE WHERE last_name=:a AND 
     (date_of_birth = :c or :c is NULL) AND (gender = :d or :d IS NULL)' USING ....
ELSIF :p_dateofbirth IS NOT NULL THEN
  OPEN cur FOR 
    'SELECT * FROM PEOPLE WHERE date_of_birth=:a AND 
     (first_name=:b OR :b IS NULL) AND (gender = :d or :d IS NULL)' USING ....
ELSE
  RAISE_APPLICATION_ERROR(-20001,'Last Name or Date of Birth MUST be supplied);
END IF;
0 голосов
/ 25 августа 2010

Вы пробовали это?

select * from my_table
where a_col = :a
  and b_col = (case when :b is not null then :b else b_col end)
  and c_col = (case when :c is not null then :c else c_col end)
  and d_col = (case when :d is not null then :d else d_col end)
;
0 голосов
/ 25 августа 2010

Вы можете заставить запрос SQL выполнять работу по проверке каждого элемента на NULL.

sqlquery := 'SELECT * FROM table WHERE a_col = a'||
            ' AND (:b IS NULL OR b_col = :b)'||
            ' AND (:c IS NULL OR b_col = :c)';

OPEN cur FOR sqlquery USING b,b,c,c;

Вам необходимо повторить переменные в предложении USING, что, к сожалению, создает возможность для опечаток, приводящих к путаницеошибок.Но, по крайней мере, вам нужно сделать это правильно только один раз.

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