2010-01-24 19 views
1

我有這樣大的代碼,我想在我的搜索3件事情內側箱或解碼:
1 - 尋找所有的訂單(交付,而不是)搜索匹配的:
2-尋找與搜索相匹配的所有吊墜訂單;
3-查找與搜索匹配的所有交付訂單;的if-else,一個裁判光標

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,如果字符串爲空;

但我還沒有看到任何這樣的例子,事情可以真的很亂。 有人可以用相同的代碼來幫助新手嗎?

回答

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

您可以使用動態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

感謝您的回覆,我發現它們非常引人注目,我的代碼變得更乾淨,更具可讀性。儘管如此,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; 
+0

你的代碼 - 如你所說 - 太大了,因爲有很多重複的。避免重複的方法是將查詢分解爲組件,並使用動態SQL來組裝引用遊標語句。明確的重複性方法的優點是您可以獲得關於依賴性的反饋。但它帶來了維護費用。所以這歸結於味道的問題。 – APC 2010-01-24 21:57:51