if-else, case или decode внутри курсора ref - PullRequest
1 голос
/ 24 января 2010

У меня есть большой код, в котором я хочу найти 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 условия для поиска, и я хотел бы знать, возможно ли использовать что-то вроде case, decode или даже другой курсор с параметром, чтобы сделать этот внутренний выбор с помощью:
- LIKE, если строка поиска не равна нулю;
- без LIKE, если строка пуста;

Но я не видел никаких примеров этого, и все может пойти довольно грязно. Может ли кто-нибудь помочь новичку с тем же кодом?

Ответы [ 3 ]

2 голосов
/ 24 января 2010

Я бы тоже использовал для этого динамический 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 голосов
/ 24 января 2010

Вы можете использовать динамический 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 голос
/ 24 января 2010

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