Oracle中自定義函數與動態執行SQL

原文鏈接:https://www.cnblogs.com/hanruyue/p/5974036.html

        Oracle已經提供了許多可用函數,但是在特定需求上,我們還是需要設計滿足要求的自定義函數。得空收集各類資料整理,還需多多使用加以熟悉。

一、函數語法

Create [or replace] function funtionName(parameter1 mode1 dataType1,parameter2 mode2 dataType2,….) 
Return returnDataType
Is/as
--定義使用變量、返回變量;
Begin
  Function_body;
  Return expression;
End functionName;--結束函數的聲明,也可以直接寫end不加函數名。

說明:
function_name用戶定義的函數名。函數名必須符合標示符的定義規則,對其所有者來說,該名在數據庫中是唯一的。
parameter:用戶定義的參數。用戶可以定義一個或多個參數。
mode:參數類型。參數的模式有3種:(如果沒有註明, 參數默認的類型爲 in),in: 爲只讀模式, 在函數中, 參數的值只能被引用, 不能被改變;out: 爲只寫模式, 只能被賦值, 不能被引用;in out:  可讀可寫。
dataType:用戶定義參數的數據類型。
returnDataType:表示返回值類型。
Function_body:函數主體由pl/sql語句構成。
expression:函數返回expression表達式的值。

注意:函數可以沒有輸入輸出參數,但一定要有返回(return)的數據類型,因此必須有內部變量存儲return的數據;

二、實例

根據輸入的數字,返回兩個數的和,若除數爲0,則拋出自定義異常。

create or replace function testdivision(js1 in number, js2 in number)
  return number is
  v_re number;
  customize_exp EXCEPTION; --自定義異常
begin
  if js2 = 0 then
    raise customize_exp;
    --raise_application_error(-20006,'不能除0');
  else
    v_re := js1 / js2;
    return v_re;
  end if;
exception
  --捕獲異常
  when customize_exp then
    dbms_output.put_line('customize error!'); --打印參數
    raise_application_error(-20006, '不能除0'); --異常提示
  when others then
    return 0;
end;
--刪除函數
DROP FUNCTION testdivision;
--查看當前用戶無效函數
SELECT object_name FROM user_objects WHERE status='INVALID' AND object_type='FUNCTION';
--查看函數代碼
SELECT * FROM user_source WHERE name=upper('testdivision');

三、執行動態SQL

       在一般的sql操作中,sql語句基本上都是固定的,如:SELECT t.empno,t.ename  FROM scott.emp t WHERE t.deptno = 20;但有的時候,從應用的需要或程序的編寫出發,都可能需要用到動態SQl,如:當 from 後的表 不確定時,或者where 後的條件不確定時,都需要用到動態SQL。例如根據表名查詢記錄數:

create or replace function count_rows(table_name in varchar2,owner in varchar2 default null)
return number authid current_user IS
  num_rows number;
  stmt varchar2(2000);
begin
  --獲取某表的記錄條數
  if owner is null then
    stmt := 'select count(*) from "' || table_name || '"';
  else
    stmt := 'select count(*) from "' || owner || '"."' || table_name || '"';
  end if;
  execute immediate stmt
    into num_rows;
  return num_rows;
exception
  when others then
    return 0;
end;

執行動態語句的話需要顯式的授權,加上AUTHID CURRENT_USER
AUTHID DEFINER (定義者權限):指編譯存儲對象的所有者。也是默認權限模式。
AUTHID CURRENT_USER(調用者權限):指擁有當前會話權限的模式,這可能和當前登錄用戶相同或不同(alter session set current_schema 可以改變調用者Schema)。

EXECUTE IMMEDIATE用法例子:

1. 給動態語句傳值(USING 子句)

 declare
  l_depnam varchar2(20) := 'testing';
  l_loc    varchar2(10) := 'Dubai';
  begin
  execute immediate 'insert into dept values  (:1, :2, :3)'
    using 50, l_depnam, l_loc;
  commit;
 end;

2. 從動態語句檢索值(INTO子句)

 declare
  l_cnt    varchar2(20);
 begin
  execute immediate 'select count(1) from emp'
    into l_cnt;
  dbms_output.put_line(l_cnt);
 end;

3. 動態調用例程.例程中用到的綁定變量參數必須指定參數類型.黓認爲IN類型,其它類型必須顯式指定

 declare
  l_routin   varchar2(100) := 'gen2161.get_rowcnt';
  l_tblnam   varchar2(20) := 'emp';
  l_cnt      number;
  l_status   varchar2(200);
 begin
  execute immediate 'begin ' || l_routin || '(:2, :3, :4); end;'
    using in l_tblnam, out l_cnt, in out l_status;

  if l_status != 'OK' then
     dbms_output.put_line('error');
  end if;
 end;

4. 將返回值傳遞到PL/SQL記錄類型;同樣也可用%rowtype變量

 declare
    type empdtlrec is record (empno  number(4),ename  varchar2(20),deptno  number(2));
    empdtl empdtlrec;
 begin
    execute immediate 'select empno, ename, deptno '||'from emp where empno = 7934'
    into empdtl;
 end;

5. 傳遞並檢索值.INTO子句用在USING子句前

 declare
   l_dept    pls_integer := 20;
   l_nam     varchar2(20);
   l_loc     varchar2(20);
 begin
    execute immediate 'select dname, loc from dept where deptno = :1'
       into l_nam, l_loc
       using l_dept ;
 end;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章