【问题标题】:if-else, case or decode inside of a ref cursorif-else、case 或 decode 在 ref 游标内
【发布时间】:2011-01-08 17:49:01
【问题描述】:

我有这么大的代码,我想在其中搜索 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;

如果我的搜索不为空,则此方法有效,但如果是,我想稍微修改一下内部选择并将其变成如下内容: (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 个搜索条件,我想知道是否可以使用大小写、解码甚至其他带有参数的光标来执行此内部选择:
- 如果搜索字符串不为空,则 LIKE;
- 如果字符串为空,则不带 LIKE;

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

【问题讨论】:

    标签: sql oracle plsql cursor plsqldeveloper


    【解决方案1】:

    我也会为此使用动态 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】:

      您可以使用动态 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;
      /
      

      【讨论】:

        【解决方案3】:

        感谢您的回复,我发现它们非常有趣,而且我猜我的代码变得更清晰、更易读。尽管如此,OMG Ponies 似乎比另一只更适合。但是我发现我的代码还是很大,可能是我太固执了!

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

        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;
        

        【讨论】:

        • 你的代码——正如你所说——太大了,因为有很多重复。避免重复的方法是将查询分解为组件并使用动态 SQL 组装 ref 游标语句。显式、重复方法的优点是您可以获得有关依赖关系的反馈。但它带来了维护开销。所以这归结为品味问题。
        猜你喜欢
        • 2018-05-21
        • 1970-01-01
        • 2013-09-10
        • 2012-10-15
        • 2023-03-03
        • 1970-01-01
        • 1970-01-01
        • 2013-10-19
        • 2012-06-02
        相关资源
        最近更新 更多