Как использовать CASE и IN внутри оператора where при сравнении переменной - PullRequest
1 голос
/ 02 апреля 2019

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

Внутри моего утверждения WHERE есть строка:

AND c.nregion = pnregion

pnregion - это номер российского региона.Это утверждение помогает моему курсору работать намного быстрее, поскольку Oracle не нужно просматривать полную таблицу.

Проблема в том, что если pnregion равно 47 или 78, то эта строка должна выглядеть следующим образом

AND c.nregion in (47, 78)

Как это сделать?Должен ли я как-то использовать CASE или я могу что-то сделать вне курсора?

Ответы [ 3 ]

2 голосов
/ 02 апреля 2019

Вы можете использовать:

WHERE ( c.nregion = pnregion
      OR (   pnregion  IN ( 47, 78 )
         AND c.nregion IN ( 47, 78 )
         )
      )

Это легко расширяется, если вы хотите более 2 значений, так как значения могут быть добавлены к обоим IN фильтрам.

1 голос
/ 02 апреля 2019

Если я понял вопрос, вас беспокоит изменяющиеся элементы в списке IN .Другими словами, вы не можете поместить значения, разделенные запятыми, в список IN, если только вы

  • не переключитесь на динамический SQL (что вам не нужно)
  • отдельноэти значения в строках

Вот пример, основанный на схеме Скотта;Надеюсь, вы это поймете.

Вот что у вас сейчас есть:

SQL> create or replace procedure p_test (pnregion in varchar2)
  2  is
  3    cursor c1 is select empno, ename from emp
  4      where deptno in pnregion;
  5  begin
  6    for cr in c1 loop
  7      dbms_output.put_line(cr.ename);
  8    end loop;
  9  end;
 10  /

Procedure created.

SQL> -- This is OK
SQL> exec p_test('10');
CLARK
KING
MILLER

PL/SQL procedure successfully completed.

SQL> -- This is not OK
SQL> exec p_test('10, 20');
BEGIN p_test('10, 20'); END;

*
ERROR at line 1:
ORA-01722: invalid number
ORA-06512: at "SCOTT.P_TEST", line 6
ORA-06512: at line 1


SQL>

Теперь разделите значения через запятую на строки и посмотрите, как это работает:

SQL> create or replace procedure p_test (pnregion in varchar2)
  2  is
  3    cursor c1 is select empno, ename from emp
  4      where deptno in (select regexp_substr(pnregion, '[^,]+', 1, level)
  5                       from dual
  6                       connect by level <= regexp_count(pnregion, ',') + 1
  7                      );
  8  begin
  9    for cr in c1 loop
 10      dbms_output.put_line(cr.ename);
 11    end loop;
 12  end;
 13  /

Procedure created.

SQL> -- This is OK
SQL> exec p_test('10');
CLARK
KING
MILLER

PL/SQL procedure successfully completed.

SQL> -- This is also OK now
SQL> exec p_test('10, 20');
SMITH
JONES
CLARK
SCOTT
KING
ADAMS
FORD
MILLER

PL/SQL procedure successfully completed.

SQL> -- Or even some more values:
SQL> exec p_test('10, 20,30');
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER

PL/SQL procedure successfully completed.

SQL>
1 голос
/ 02 апреля 2019

Вы можете использовать функцию декодировать , чтобы добавить другую опцию для кодов 47/78:

AND (c.nregion  = pnregion OR c.nregion = decode(pnregion, 47, 78, 78, 47)) 

...