ref-cursor中的if-else,case或decode

时间:2010-01-24 08:04:54

标签: sql oracle plsql cursor plsqldeveloper

我有这个大代码,我想在搜索中找到3件事:
    1-查找与搜索匹配的所有订单(已交付和未交付):
2-查找与搜索匹配的所有下注订单;
3-查找与搜索匹配的所有已下订单;

create or replace
function search_order(search IN VARCHAR2, a_option NUMBER) RETURN types.ref_cursor
AS
    orders_cursor types.ref_cursor;

BEGIN
    if search is not null then
      if a_option = 0 then /*case 1*/
         OPEN orders_cursor FOR
          select value(f), value(p),i.qtd_if, i.prec_total_if , forn.nome_fornecedor
              from item_fornecimento i, produto p ,fornecimento f, fornecedor forn
              where f.id_fornecimento in (select f.id_fornecimento from fornecimento f where f.id_fornecedor in 
             (select f1.id_fornecedor from fornecedor  f1 where f1.nome_fornecedor LIKE '%'||search||'%')) 
              and f.id_fornecimento= i.id_fornecimento and i.id_prod= p.id_prod and
              f.id_fornecedor = forn.id_fornecedor
              order by forn.nome_fornecedor,f.data_encomenda desc,p.nome_prod asc;  
        RETURN orders_cursor;


      ELSIF a_option = 1 then /*case 2*/
        OPEN orders_cursor FOR
        (...)
            where f.id_fornecimento in (select f.id_fornecimento from fornecimento f where f.id_fornecedor in 
            (select f1.id_fornecedor from fornecedor  f1 where f1.nome_fornecedor LIKE '%'||search||'%')and f.data_entrega is null) 
            (...) 
        RETURN orders_cursor;

        ELSE /* case 3*/
        OPEN orders_cursor FOR
          (...)
              where f.id_fornecimento in (select f.id_fornecimento from fornecimento f where f.id_fornecedor in 
              (select f1.id_fornecedor from fornecedor  f1 where f1.nome_fornecedor LIKE '%'||search||'%')and f.data_entrega is not null) 
              (...) 
          RETURN orders_cursor;    
      end if;
    end if;

END;

如果我的搜索不是null,这是有效的,但是如果是,我只想稍微修改内部选择并将其转换为如下所示: (select f1.id_fornecedor from fornecedor f1 where f1.nome_fornecedor LIKE '%'||search||'%')and f.data_entrega is not null)至 - > (select f1.id_fornecedor from fornecedor f1)and f.data_entrega is not null)

所以我有3个搜索条件,我想知道是否可以使用case,decode甚至是带参数的另一个光标,用以下内容进行内部选择:
- 如果搜索字符串不为空,则为LI; - 没有LIKE,如果字符串为null;

但我没有看到任何这方面的例子,事情真的会变得非常混乱。 有人可以用相同的代码帮助新手吗?

3 个答案:

答案 0 :(得分:2)

您可以使用动态SQL来自定义要执行的语句。

以下示例返回一组DEPT记录,具体取决于传递给函数的两个参数。内部逻辑改变where子句以既不使用其中一个参数,也不使用两个参数。

create or replace function get_dept_details
    ( p_loc dept.location%type := null
      , p_name dept.dname%type := null )
    return sys_refcursor
is
    rc sys_refcursor;
    stmt varchar2(32767);
begin
    stmt := 'select * from dept';
    if p_loc is null and p_name is null 
    then
        open rc for stmt;
    elsif p_loc is not null and p_name is null
    then
        stmt := stmt||' where loc = :1';
        open rc for stmt using p_loc;
    elsif p_loc is null and p_name is not null
    then
        stmt := stmt||' where dname = :1';
        open rc for stmt using p_name;
    else
        stmt := stmt||' where loc = :1 and dname = :2';
        open rc for stmt using p_loc, p_name;
    end if;
    return rc;
end;
/

答案 1 :(得分:2)

我也会使用动态SQL,但您可以使用PLSQL案例来控制执行流程:

BEGIN

  CASE
    WHEN search IS NOT NULL AND a_option = 0 THEN
      OPEN orders_cursor FOR
        SELECT VALUE(f), 
               VALUE(p),
               i.qtd_if, 
               i.prec_total_if, 
               forn.nome_fornecedor
          FROM ITEM_FORNECIMENTO i
          JOIN PRODUTO p ON p.id_prod = i.id_prod
          JOIN FORNECIMENTO f ON f.id_fornecimento = i.id_fornecimento
          JOIN FORNECEDOR forn ON forn.id_fornecedor = f.id_fornecedor
                              AND forn.nome_fornecedor LIKE '%'||search||'%'
      ORDER BY forn.nome_fornecedor,f.data_encomenda desc,p.nome_prod;

    WHEN search IS NULL AND a_option = 1 THEN
      OPEN orders_cursor FOR
        SELECT VALUE(f), 
               VALUE(p),
               i.qtd_if, 
               i.prec_total_if, 
               forn.nome_fornecedor
          FROM ITEM_FORNECIMENTO i
          JOIN PRODUTO p ON p.id_prod = i.id_prod
          JOIN FORNECIMENTO f ON f.id_fornecimento = i.id_fornecimento
                             AND f.data_entrega IS NULL
          JOIN FORNECEDOR forn ON forn.id_fornecedor = f.id_fornecedor
      ORDER BY forn.nome_fornecedor,f.data_encomenda desc,p.nome_prod;

    WHEN search IS NOT NULL AND a_option = 1 THEN
      OPEN orders_cursor FOR
        SELECT VALUE(f), 
               VALUE(p),
               i.qtd_if, 
               i.prec_total_if, 
               forn.nome_fornecedor
          FROM ITEM_FORNECIMENTO i
          JOIN PRODUTO p ON p.id_prod = i.id_prod
          JOIN FORNECIMENTO f ON f.id_fornecimento = i.id_fornecimento
                             AND f.data_entrega IS NULL
          JOIN FORNECEDOR forn ON forn.id_fornecedor = f.id_fornecedor
                              AND forn.nome_fornecedor LIKE '%'||search||'%'
      ORDER BY forn.nome_fornecedor,f.data_encomenda desc,p.nome_prod;
  END CASE;

END;

这不完整,但你明白了。我还将ANSI-89 JOIN语法转换为ANSI-92,并删除了该过程中的IN子句。

答案 2 :(得分:1)

感谢您的回复,我发现它们非常有趣,而且我的代码变得更清晰,更具可读性。尽管如此,OMG小马似乎比另一个更好。但我发现我的代码仍然很大,也许我很顽固!

这是最终结果,可能感兴趣的人

create or replace
function search_order(search IN VARCHAR2, a_option NUMBER) RETURN types.ref_cursor
AS
    orders_cursor types.ref_cursor;

BEGIN
      CASE    
      /*all the orders that match, no matter if they're delivered or not*/
      WHEN search IS NOT NULL AND a_option = 0 THEN
      OPEN orders_cursor FOR
        SELECT VALUE(f), 
               VALUE(p),
               i.qtd_if, 
               i.prec_total_if, 
               forn.nome_fornecedor
          FROM ITEM_FORNECIMENTO i
          JOIN PRODUTO p ON p.id_prod = i.id_prod
          JOIN FORNECIMENTO f ON f.id_fornecimento = i.id_fornecimento
          JOIN FORNECEDOR forn ON forn.id_fornecedor = f.id_fornecedor
          AND forn.nome_fornecedor LIKE '%'||search||'%'
      ORDER BY forn.nome_fornecedor,f.data_encomenda desc,p.nome_prod;
      RETURN orders_cursor;

      /*all the orders, no matter if they're delivered or not*/
      WHEN search IS NULL AND a_option = 0 THEN
      OPEN orders_cursor FOR
      SELECT VALUE(f), 
               VALUE(p),
               i.qtd_if, 
               i.prec_total_if, 
               forn.nome_fornecedor
          FROM ITEM_FORNECIMENTO i
          JOIN PRODUTO p ON p.id_prod = i.id_prod
          JOIN FORNECIMENTO f ON f.id_fornecimento = i.id_fornecimento
          JOIN FORNECEDOR forn ON forn.id_fornecedor = f.id_fornecedor
      ORDER BY forn.nome_fornecedor,f.data_encomenda desc,p.nome_prod;
      RETURN orders_cursor;

      /*########################## OPTION 1 #################################*/

      /*all the matched and pendent orders*/
      WHEN search IS NOT NULL AND a_option = 1 THEN
      OPEN orders_cursor FOR
        SELECT VALUE(f), 
               VALUE(p),
               i.qtd_if, 
               i.prec_total_if, 
               forn.nome_fornecedor
          FROM ITEM_FORNECIMENTO i
          JOIN PRODUTO p ON p.id_prod = i.id_prod
          JOIN FORNECIMENTO f ON f.id_fornecimento = i.id_fornecimento
          JOIN FORNECEDOR forn ON forn.id_fornecedor = f.id_fornecedor
          AND forn.nome_fornecedor LIKE '%'||search||'%'AND f.data_entrega IS NULL
      ORDER BY forn.nome_fornecedor,f.data_encomenda desc,p.nome_prod;
      RETURN orders_cursor;

      /*all the pendent orders*/
      WHEN search IS NULL AND a_option = 1 THEN
      OPEN orders_cursor FOR
        SELECT VALUE(f), 
               VALUE(p),
               i.qtd_if, 
               i.prec_total_if, 
               forn.nome_fornecedor
          FROM ITEM_FORNECIMENTO i
          JOIN PRODUTO p ON p.id_prod = i.id_prod
          JOIN FORNECIMENTO f ON f.id_fornecimento = i.id_fornecimento
          JOIN FORNECEDOR forn ON forn.id_fornecedor = f.id_fornecedor
          AND f.data_entrega IS NULL
      ORDER BY forn.nome_fornecedor,f.data_encomenda desc,p.nome_prod;
      RETURN orders_cursor;

      /*########################## OPTION 2 #################################*/
      /*all the matched and delivered orders*/
      WHEN search IS NOT NULL AND a_option = 2 THEN
      OPEN orders_cursor FOR
        SELECT VALUE(f), 
               VALUE(p),
               i.qtd_if, 
               i.prec_total_if, 
               forn.nome_fornecedor
          FROM ITEM_FORNECIMENTO i
          JOIN PRODUTO p ON p.id_prod = i.id_prod
          JOIN FORNECIMENTO f ON f.id_fornecimento = i.id_fornecimento
          JOIN FORNECEDOR forn ON forn.id_fornecedor = f.id_fornecedor
          AND forn.nome_fornecedor LIKE '%'||search||'%'AND f.data_entrega IS NOT NULL
      ORDER BY forn.nome_fornecedor,f.data_encomenda desc,p.nome_prod;
      RETURN orders_cursor;

      /*all the delivered orders*/
      WHEN search IS NULL AND a_option = 2 THEN
      OPEN orders_cursor FOR
        SELECT VALUE(f), 
               VALUE(p),
               i.qtd_if, 
               i.prec_total_if, 
               forn.nome_fornecedor
          FROM ITEM_FORNECIMENTO i
          JOIN PRODUTO p ON p.id_prod = i.id_prod
          JOIN FORNECIMENTO f ON f.id_fornecimento = i.id_fornecimento
          JOIN FORNECEDOR forn ON forn.id_fornecedor = f.id_fornecedor
          AND f.data_entrega IS NOT NULL
      ORDER BY forn.nome_fornecedor,f.data_encomenda desc,p.nome_prod;
      RETURN orders_cursor;
      end case;
END;