Создание хранимых процедур ORACLE PL / SQL с различными условиями AND - PullRequest
2 голосов
/ 02 декабря 2010

Мне нужно создать запрос Oracle, например

select * from emp where emp_id=i_emp_id and emp_nm=i_emp_nm and emp_dpt=i_emp_dpt

если все три входа не равны нулю, он должен работать как

select * from emp where emp_id=i_emp_id and emp_nm=i_emp_nm and emp_dpt=i_emp_dpt

если я передаю i_emp_id как ноль, тогда запрос должен работать как

select * from emp where emp_nm=i_emp_nm and emp_dpt=i_emp_dpt

если я передаю i_emp_id как ноль и i_emp_dpt как ноль, тогда запрос должен работать как

select * from emp where emp_nm=i_emp_nm

Ответы [ 2 ]

1 голос
/ 03 декабря 2010

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

create or replace function get_dyn_emps
   (i_empno in emp.empno%type
    ,  i_ename in emp.ename%type
    , i_deptno in emp.deptno%type)
    return sys_refcursor
is
    rc sys_refcursor;
    stmt varchar2(32767);
begin
    stmt := 'select * from emp where 1=1';
    if i_empno is not null
    then
        stmt := stmt||' and empno = :p_empno';
    else
        stmt := stmt||' and (1=1 or :p_empno is null)';
    end if;
    if i_ename is not null
    then
        stmt := stmt||' and ename = :p_ename';
    else
        stmt := stmt||' and (1=1 or :p_ename is null)';
    end if;        
    if i_deptno is not null
    then
        stmt := stmt||' and deptno = :p_deptno';
    else
        stmt := stmt||' and (1=1 or :p_deptno is null)';
    end if;

    open rc for stmt 
        using i_empno, i_ename , i_deptno;
    return rc;
end get_dyn_emps;
/

Это может показаться многословным решением по сравнению с принятым в настоящее время ответом, но вот почему это лучший подход: возвращает правильный ответ .

В отделе 40 есть сотрудник без имени:

SQL> var rc refcursor
SQL> exec :rc := get_dyn_emps(null, null, 40)

PL/SQL procedure successfully completed.

SQL> print rc

  EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM    DEPTNO
------- ---------- --------- ---------- --------- ---------- ---------- ---------
   8101                                 03-DEC-10                              40

SQL>

Если я реализую более аккуратное решение DECODE () ...

create or replace function get_fix_emps
   (i_empno in emp.empno%type
    ,  i_ename in emp.ename%type
    , i_deptno in emp.deptno%type)
    return sys_refcursor
is
    rc sys_refcursor;
begin
    open rc for 
        SELECT * FROM emp 
         WHERE empno = DECODE(NVL(i_empno,0), 0, empno, i_empno)
           AND ename = DECODE(NVL(i_ename,'X'), 'X', ename, i_ename) 
           AND deptno = DECODE(NVL(i_deptno,0), 0, deptno, i_deptno);
    return rc;
end get_fix_emps;
/

... вот что происходит:

SQL> exec :rc := get_fix_emps(null, null, 40)

PL/SQL procedure successfully completed.

SQL> print rc

no rows selected

SQL>

Поскольку NULL никогда не равен NULL, это то, что ename = DECODE(NVL(i_ename,'X'), 'X', ename, i_ename) оценивает в этом случае.

0 голосов
/ 02 декабря 2010

Как и в моих приложениях, вы можете достичь этой функциональности, просто используя функции NVL и DECODE.

SELECT * FROM emp 
 WHERE emp_id = DECODE(NVL(i_emp_id,0), 0, emp_id, i_emp_id)
   AND emp_nm = DECODE(NVL(i_emp_nm,0), 0, emp_nm, i_emp_nm) 
   AND emp_dpt = DECODE(NVL(i_emp_dpt,'X'), 'X', emp_dpt, i_emp_dpt)

Если i_emp_id равно нулю, оно будет соответствовать текущему значению, поэтому все записи будут совпадатьв противном случае возвращается только та запись, которая соответствует i_emp_id.То же самое относится к emp_nm и emp_dpt.

...