PL/SQL -- 函数
--==================
-- PL/SQL --> 函數
--==================
?
??? 函數通常用于返回特定的數據。其實質是一個有名字的PL/SQL塊,作為一個schema對象存儲于數據庫,可以被反復執行。函數通常被作為
一個表達式來調用或存儲過程的一個參數,具有返回值。
?
一、建立函數的語法
??? CREATE [ OR REPLACE ] FUNCTION function_name
??????? (argument1 [mode1] datatype1,
??????? ?argument2 [mode2] datetype2,
??????? ?...)
??? RETURN datatype
??? IS | AS
??????? [local_variable_declarations;...]
??? BEGIN
??????? --actions;
??????? RETURN expression;
??? END [function_name];
???
??? 建立函數的幾點注意事項
??????? 1.指定參數數據類型時(argument),不能指定其長度
??????? 2.函數頭部必須指定return子句,函數體內至少要包含一條return語句
??????? 3.可以指定in參數,也可以指定out參數,以及in out 參數
??????? 4.可以為參數指定缺省值。指定缺省值時使用default關鍵字。如arg1 varchar2 default 'SCOTT'
?
二、使用函數的優點
??? 1.增加了代碼的靈活性,可以完成一些較為復雜的任務,以及僅僅通過SQL無法完成的任務
??? 2.可以直接將函數使用到where子句中來過濾數據
??? 3.可以作為存儲過程的參數使用,是存儲過程的一種補充
???
三、建立函數
??? 1.建立不帶參數的函數
??????? scott@ORCL> create or replace function get_user
??????? ? 2? return varchar2
??????? ? 3? is
??????? ? 4??? v_user varchar2(20);
??????? ? 5? begin
??????? ? 6??? select username into v_user from user_users;
??????? ? 7??? return v_user;
??????? ? 8? end;
??????? ? 9? /
?
??????? Function created.
?
??????? --使用全局變量接收函數的返回值
??????????? scott@ORCL> var v1 varchar2(20)?
??????????? scott@ORCL> exec :v1:=get_user
?
??????????? PL/SQL procedure successfully completed.
?
??????????? scott@ORCL> print v1;
?
??????????? V1
??????????? --------------------------------
??????????? SCOTT
???????
??????? --使用本地變量接收函數的返回值
??????????? scott@ORCL> set serveroutput on;
??????????? scott@ORCL> declare user_name varchar2(20);
??????????? ? 2? begin
??????????? ? 3? user_name:=get_user();
??????????? ? 4? dbms_output.put_line('Current user: '||user_name);
??????????? ? 5? end;
??????????? ? 6? /
??????????? Current user: SCOTT
?
??????????? PL/SQL procedure successfully completed.???
???????????
??????? --在SQL語句中直接調用函數??
??????????? scott@ORCL> select get_user from dual;
?
??????????? GET_USER
??????????? ---------------------
??????????? SCOTT??
?
??????? --使用dbms_output調用函數(此調用作為存儲過程的一個參數來進行調用)??
??????????? scott@ORCL> set serveroutput on;
??????????? scott@ORCL> exec dbms_output.put_line('Current user: '||get_user);
??????????? Current user: SCOTT????
???????????
??? 2.建立帶有in 參數的函數
??????? scott@ORCL> create or replace function raise_sal(name in varchar2)??? --注意此處定義時參數并為指定類型的長度
??????? ? 2? return number
??????? ? 3? as
??????? ? 4??? v_sal emp.sal%type;
??????? ? 5? begin
??????? ? 6??? select sal*1.2 into v_sal from emp
??????? ? 7??? where upper(ename)=upper(name);
??????? ? 8??? return v_sal;
??????? ? 9? exception
??????? ?10??? when no_data_found then
??????? ?11??? raise_application_error(-20000,'Current Employee is not exists');
??????? ?12? end;
??????? ?13? /
?
??????? Function created.??
?
??????? scott@ORCL> select sal,raise_sal('SCOTT') from emp where ename='SCOTT';
?
??????????? ?? SAL RAISE_SAL('SCOTT')
??????? ---------- ------------------
??????????? ? 3100?????????????? 3720??
?
??????? scott@ORCL> select raise_sal('Robinson') from dual;
??????? select raise_sal('Robinson') from dual
??????????? ?? *
??????? ERROR at line 1:
??????? ORA-20000: Current Employee is not exists
??????? ORA-06512: at "SCOTT.GET_SAL", line 11?????
?
??? 3.建立帶有out參數的函數
??????? scott@ORCL> create or replace function get_info
??????? ? 2? (name varchar2,title out varchar2)
??????? ? 3? return varchar2
??????? ? 4? as
??????? ? 5??? deptname dept.dname%type;
??????? ? 6? begin
??????? ? 7??? select e.job,d.dname into title,deptname
??????? ? 8??? from emp e inner join dept d
??????? ? 9????? on e.deptno=d.deptno
??????? ?10??? where upper(e.ename)=upper(name);
??????? ?11??? return deptname;
??????? ?12? exception
??????? ?13??? when no_data_found then
??????? ?14????? raise_application_error(-20000,'Current Employee is not exists');
??????? ?15? end;
??????? ?16? /
?
??????? Function created.
?
??????? 注意對于使用out參數的函數,不能使用SQL語句來調用。而必須定義變量接收out參數和函數的返回值。
??????? 調用如下
??????? scott@ORCL> var job varchar2(20);
??????? scott@ORCL> var dname varchar2(20);
??????? scott@ORCL> exec :dname:=get_info('scott',:job);
?
??????? PL/SQL procedure successfully completed.
?
??????? scott@ORCL> print dname job;
?
??????? DNAME
??????? --------------------------------
??????? RESEARCH
?
?
??????? JOB
??????? --------------------------------
??????? ANALYST
?
??? 3.建立帶有in out參數的函數
??????? scott@ORCL> create or replace function comp
??????? ? 2? (num1 number,num2 in out number)
??????? ? 3? return number
??????? ? 4? as
??????? ? 5??? v_result number(6);
??????? ? 6??? v_remainder number;
??????? ? 7? begin
??????? ? 8??? v_result:=num1*num2;
??????? ? 9??? v_remainder:=mod(num1,num2);
??????? ?10??? num2:=v_remainder;
??????? ?11??? return v_result;
??????? ?12? exception
??????? ?13??? when zero_divide then
??????? ?14????? raise_application_error(-20000,'Divison by zero');
??????? ?15? end;
??????? ?16? /
?
??????? Function created.
?
??????? scott@ORCL> var result1 number;
??????? scott@ORCL> var result2 number;
??????? scott@ORCL> exec :result2:=10
?
??????? PL/SQL procedure successfully completed.
?
??????? scott@ORCL> exec :result1:=comp(16,:result2);
?
??????? PL/SQL procedure successfully completed.
?
??????? scott@ORCL> print result1 result2;
?
??????? ?? RESULT1
??????? ----------
??????????? ?? 160
?
?
??????? ?? RESULT2
??????? ----------
??????????????? ?6
?
四、函數的調用及限制
??? 1.函數的調用(其具體調用方法參照上面的演示)
??????? a.使用全局變量接收函數的返回值
??????? b.使用本地變量接受函數的返回值
??????? c.在SQL語句中直接調用函數
??????? d.使用dbms_output調用函數
??????? 注:函數在調用的時候需要按位置指定參數,沒有存儲過程參數傳遞靈活
??????????? 必須具有execute 函數的權限
???
??? 2.函數在SQL中調用的主要場合
??????? 由于函數必須要返回數據,因此只能作為表達式的一部分調用。此外函數可以在SQL語句的以下部分調用
??????? a. select 命令的選擇列表或子查詢中
??????? b. 條件表達式where, having子句中
??????? c. connect by , start with ,order by 以及group by 子句中
??????? d. insert 命令的values子句中
??????? f. update 命令的set 子句中
???????
??? 3.函數在SQL中調用的限制
??????? a. SQL語句中只能調用存儲在服務器端的函數,而不能調用存儲于客戶端的函數
??????? b. SQL語句中調用的函數只能帶有輸入參數IN,而不能帶有輸出參數OUT 以及輸入輸出參數IN OUT
??????? c. SQL語句中調用的函數只能使用SQL支持的標準數據類型,不能使用PL/SQL特有的類型,如boolean,table,record等
??????? d. SQL語句中調用的函數不能包含insert ,update 和delete 語句
???????
??????? 下面演示SQL調用時不能完整DML操作示例
?
??????? --創建一張表tb_emp
??????????? scott@ORCL> create table tb_emp as select * from emp;
?
??????? --創建一個函數,用于刪除tb_emp表中指定的empno號的雇員信息,并返回其薪資
??????????? scott@ORCL> create or replace function delete_oper(no number)
??????????? ? 2? return number
??????????? ? 3? as
??????????? ? 4??? v_sal emp.sal%type;
??????????? ? 5??? begin
??????????? ? 6??? select sal into v_sal from tb_emp where empno=no;
??????????? ? 7??? delete from tb_emp where empno=no;
??????????? ? 8??? return v_sal;
??????????? ? 9??? end;
??????????? ?10? /
?
??????????? Function created.
???????
??????? --使用SQL語句調用時,收到了錯誤信息,在內部查詢內不能完成DML操作
??????????? scott@ORCL> select delete_oper(7788) from dual;
??????????? select delete_oper(7788) from dual
??????????????? ?? *
??????????? ERROR at line 1:
??????????? ORA-14551: cannot perform a DML operation inside a query
??????????? ORA-06512: at "SCOTT.DELETE_OPER", line 7??????
???????
??????? --使用exec執行時函數被成功執行
??????? ??? scott@ORCL> var v_no number;
??????????? scott@ORCL> exec :v_no:=delete_oper(7788);
?
??????????? PL/SQL procedure successfully completed.
?
??????????? scott@ORCL> print v_no;
?
??????????????? ? V_NO
??????????? ----------
??????????????? ? 3100
?
??????????? scott@ORCL> select * from tb_emp where empno=7788;
?
??????????? no rows selected???
???????????
??????? --下面的演示表明,不能使用DML語句來調用函數
??????????? scott@ORCL> update emp set sal=raise_sal('SCOTT') where ename='SCOTT';
??????????? update emp set sal=raise_sal('SCOTT') where ename='SCOTT'
??????????????????????????? ?? *
??????????? ERROR at line 1:
??????????? ORA-04091: table SCOTT.EMP is mutating, trigger/function may not see it
??????????? ORA-06512: at "SCOTT.RAISE_SAL", line 6????
???????????
五、函數的管理?
??? 函數使用了與存儲過程相關的視圖,可以從系統視圖中獲得函數的相關信息
??????? DBA_OBJECTS
??????? DBA_SOURCE
??????? USER_OBJECTS
??????? USER_SOURCE
?
??? --查看函數的源碼
??????? scott@ORCL> select text from user_source where name='DELETE_OPER' order by line;
?
??????? TEXT
??????? ------------------------------------------------------------
??????? function delete_oper(no number)
??????? ? return number
??????? ?as
??????? ? v_sal emp.sal%type;
??????? ? begin
??????? ? select sal into v_sal from tb_emp where empno=no;
??????? ? delete from tb_emp where empno=no;
??????? ?commit;
??????? ?? return v_sal;
??????? ? end;
?
??? --查看函數的參數信息
??????? scott@ORCL> desc delete_oper;
??????? FUNCTION delete_oper RETURNS NUMBER
??????? ?Argument Name????????????????? Type??????????????????? In/Out Default?
??????? ?------------------------------ ----------------------- ------ --------
??????? ?NO???????????????????????????? NUMBER????????????????? IN?
?
???????
六、函數與存儲過程的差異
??? 存儲過程??? ????????????????????????? ? ????????????函數
??? ----------------------------------?????????????? ?-------------------------------
??? 不能被作為表達式調用??? ??????????????????????????? 只能作為表達式被調用
??? 聲明頭部關鍵字為procedure??????????????????????? 聲明頭部關鍵字為function
??? 聲明頭部不包含return關鍵字來描述返回類型???????? 頭部必須包含return關鍵字,且PL/SQL塊中至少包含一個有效的return語句
??? 可以通過out,in out返回零個或多個值?????????????? 通過return語句返回一個與頭部聲明中類型一致的值,也可使用in,in out返回值
??? SQL語句中不可調用存儲過程?????????????????????? ?SQL語句可以調用函數
??? 多用于數據庫中完成特定的操作,如刪除,更新,插入等DML操作???? 多用于特定的數據如選擇等
???
七、更多參考
???? ?
有關SQL請參考
??????? SQL 基礎--> 子查詢
??????? SQL 基礎-->多表查詢
SQL基礎-->分組與分組函數
SQL 基礎-->常用函數
SQL 基礎--> ROLLUP與CUBE運算符實現數據匯總
SQL基礎-->層次化查詢(START BY ... CONNECT BY PRIOR)
?
??? 有關PL/SQL請參考
??????? PL/SQL --> 語言基礎
PL/SQL --> 流程控制
PL/SQL --> 存儲過程
PL/SQL --> 函數
PL/SQL --> 游標
PL/SQL -->隱式游標(SQL%FOUND)
PL/SQL --> 異常處理(Exception)
PL/SQL --> PL/SQL記錄
PL/SQL --> 包的創建與管理
PL/SQL --> 包重載、初始化
PL/SQL --> DBMS_DDL包的使用
PL/SQL --> DML 觸發器
PL/SQL --> INSTEAD OF 觸發器
?
???
總結
以上是生活随笔為你收集整理的PL/SQL -- 函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VB100年底测试:McAfee金山遗憾
- 下一篇: Hibernate+Spring整合使用