2010-12-02 2 views
2

мне нужно создать запрос Oracle, напримерСоздание процедур/SQL магазина ORACLE PL с различного рода и условий

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 

ответ

1

Лучший способ обработки различных перестановок входных переменных состоит в том, чтобы динамически собирать запрос. В следующем примере будет выполняться запрос, который хорошо работает и обрабатывает значения 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; 
/

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

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

Как я делал в своих приложениях, вы можете достичь этой функциональности, просто с помощью 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.

+0

Вы можете получить проблемы с производительностью, так как запрос не может легко использовать индексы с такой конструкцией. Иногда IF..ELSIF ... ELSE..END IF; является лучшим вариантом – 2010-12-02 08:34:21

+0

Yeh Я знаю, но этот подход я использовал в основном с Oracle Reports, где я должен основывать отчет по определенным критериям. – asifabbas 2010-12-02 08:59:27