日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Oracle存储过程和自定义函数

發布時間:2025/3/21 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Oracle存储过程和自定义函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述

Oracle-procedure解讀

Oracle存儲過程和自定義函數

PL/SQL中的過程和函數(通常稱為子程序)是PL/SQL塊的一種特殊的類型,這種類型的子程序可以以編譯的形式存放在數據庫中,并為后續的程序塊調用。

相同點: 完成特定功能的程序
不同點:是否用return語句返回值。

舉個例子:

create or replace procedure PrintStudents(p_staffName in xgj_test.username%type) ascursor c_testData isselect t.sal, t.comm from xgj_test t where t.username = p_staffName;beginfor v_info in c_testData loopDBMS_OUTPUT.PUT_LINE(v_info.sal || ' ' || v_info.comm);end loop;end PrintStudents;

一旦創建了改程序并將其存儲在數據庫中,就可以使用如下的方式調用該過程

beginPrintStudents('Computer Science');PrintStudents('Match'); end; /

或者

exec PrintStudents('Computer Science'); exec PrintStudents('Match');

在命令窗口中:

在pl/sql工具的sql窗口中:


存儲過程的創建和調用

基本語法

create [ or replace] procedure procedure_name [( argument [ {IN | OUT | IN OUT }] type, ...... argument [ {IN | OUT | IN OUT }] type ) ] { IS | AS} procedure_body

無參的存儲過程

/**無參數的存過打印hello world調用存儲過程:1. exec sayhelloworld();2 begin sayhelloworld();end;/*/ create or replace procedure sayhelloworld as --說明部分 begindbms_output.put_line('hello world'); end sayhelloworld;

調用過程:

SQL> set serveroutput on ; SQL> exec sayhelloworld();hello worldPL/SQL procedure successfully completedSQL> begin2 sayhelloworld();3 sayhelloworld();4 end;5 /hello world hello worldPL/SQL procedure successfully completed

帶參數的存儲過程

/** 創建一個帶參數的存儲過程給指定的員工增加工資,并打印增長前后的工資*/ create or replace procedure addSalary(staffName in xgj_test.username%type ) as --定義一個變量保存調整之前的薪水 oldSalary xgj_test.sal%type;begin--查詢員工漲之前的薪水select t.sal into oldSalary from xgj_test t where t.username=staffName; --調整薪水update xgj_test t set t.sal = sal+1000 where t.username=staffName ;--輸出dbms_output.put_line('調整之前的薪水:'|| oldSalary || ' ,調整之后的薪水:' || (oldSalary + 1000));end addSalary;

可以看到,update語句之后并沒有commit的操作。
一般來講為了保證事務的一致性,由調用者來提交比較合適,當然了是需要區分具體的業務需求的~

begin addSalary('xiao'); addSalary('gong'); commit ; end ; /

存儲函數

基本語法

create [ or replace] function function_name [( argument [ {IN | OUT | IN OUT }] type, ...... argument [ {IN | OUT | IN OUT }] type ) ] RETURN { IS | AS} function_body

其中 return子句是必須存在的,一個函數如果沒有執行return就結束將發生錯誤,這一點和存過有說不同。


存儲函數

準備的數據如下:

/** 查詢員工的年薪 (月工資*12 + 獎金) */create or replace function querySalaryInCome(staffName in varchar2)return number as--定義變量保存員工的工資和獎金pSalary xgj_test.sal%type;pComm xgj_test.comm%type;begin--查詢員工的工資和獎金select t.sal, t.comminto pSalary, pCommfrom xgj_test twhere t.username = staffName;--直接返回年薪return pSalary * 12 + pComm; end querySalaryInCome;

存在一個問題,當獎金為空的時候,算出來的年收入竟然是空的。
因為 如果一個表達式中有空值,那么這個表達式的結果即為空值。

所以我們需要對空值進行處理, 使用nvl函數即可。

最后修改后的function為

create or replace function querySalaryInCome(staffName in varchar2)return number as--定義變量保存員工的工資和獎金pSalary xgj_test.sal%type;pComm xgj_test.comm%type;begin--查詢員工的工資和獎金select t.sal, t.comminto pSalary, pCommfrom xgj_test twhere t.username = staffName;--直接返回年薪return pSalary * 12 + nvl(pComm,0); end querySalaryInCome;

out參數

out參數

一般來講,存儲過程和存儲函數的區別在于存儲函數可以有一個返回值,而存儲過程沒有返回值。

  • 存儲過程和存儲函數都可以有out參數
  • 存儲過程和存儲函數都可以有多個out參數
  • 存儲過程可以通過out參數實現返回值

那我們如何選擇存儲過程和存儲函數呢?

原則:

如果只有一個返回值,用存儲函數,否則(即沒有返回值或者有多個返回值)使用存儲過程。

/** 根據員工姓名,查詢員工的全部信息 */ create or replace procedure QueryStaffInfo(staffName in xgj_test.username%type,pSal out number,pComm out xgj_test.comm%type,pJob out xgj_test.job%type) isbegin--查詢該員工的薪資,獎金和職位select t.sal,t.comm,t.job into pSal,pComm,pJob from xgj_test t where t.username=staffName; end QueryStaffInfo;

先拋出兩個思考問題:

  • 查詢員工的所有信息–> out參數太多怎么辦?
  • 查詢某個部門中所有員工的信息–> out中返回集合?

后面會講到如何解決? 總不能一個個的寫out吧~


在應用中訪問存儲過程和存儲函數

概述

我們使用JAVA程序連接ORACLE數據庫。

使用jar: ojdbc14.jar

關于oracle官方提供的幾個jar的區別

classes12.jar (1,600,090 bytes) - for use with JDK 1.2 and JDK 1.3

classes12_g.jar (2,044,594 bytes) - same as classes12.jar, except that classes were compiled with “javac -g” and contain some tracing information.

classes12dms.jar (1,607,745 bytes) - same as classes12.jar, except that it contains additional code`to support Oracle Dynamic Monitoring Service.

classes12dms_g.jar (2,052,968 bytes) - same as classes12dms.jar except that classes were compiled with “javac -g” and contain some tracing information.

ojdbc14.jar (1,545,954 bytes) - classes for use with JDK 1.4 and 1.5

ojdbc14_g.jar (1,938,906 bytes) - same as ojdbc14.jar, except that classes were compiled with “javac -g” and contain some tracing information.

ojdbc14dms.jar (1,553,561 bytes) - same as ojdbc14.jar, except that it contains additional code`to support Oracle Dynamic Monitoring Service.

ojdbc14dms_g.jar (1,947,136 bytes) - same as ojdbc14dms.jar, except that classes were compiled with “javac -g” and contain some tracing information.

工程目錄如下:

簡單的寫下獲取數據庫連接的工具類

import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement;public class DBUtils {// 設定數據庫驅動,數據庫連接地址端口名稱,用戶名,密碼private static final String driver = "oracle.jdbc.driver.OracleDriver";private static final String url = "jdbc:oracle:thin:@ip:xxxx";private static final String username = "xxxx";private static final String password = "xxxx";/*** 注冊數據庫驅動*/static {try {Class.forName(driver);} catch (ClassNotFoundException e) {throw new ExceptionInInitializerError(e.getMessage());}}/*** 獲取數據庫連接*/public static Connection getConnection() {try {Connection connection = DriverManager.getConnection(url, username, password);// 成功,返回connectionreturn connection;} catch (SQLException e) {e.printStackTrace();}// 獲取失敗,返回nullreturn null;}/*** 釋放連接*/public static void cleanup(Connection conn, Statement st, ResultSet rs) {if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();} finally {rs = null;}}if (st != null) {try {st.close();} catch (SQLException e) {e.printStackTrace();} finally {st = null;}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();} finally {conn = null;}}} }

在應用程序中訪問存儲過程

根據官方提供的API,我們可以看到:

import java.sql.CallableStatement; import java.sql.Connection; import java.sql.SQLException;import org.junit.Test;import com.turing.oracle.dbutil.DBUtils;import oracle.jdbc.OracleTypes;public class TestProcedure {@Testpublic void callProcedure(){// {call <procedure-name>[(<arg1>,<arg2>, ...)]}Connection conn = null ;CallableStatement callableStatement = null ;/***根據員工姓名,查詢員工的全部信息create or replace procedure QueryStaffInfo(staffName in xgj_test.username%type,pSal out number,pComm out xgj_test.comm%type,pJob out xgj_test.job%type) isbegin--查詢該員工的薪資,獎金和職位select t.sal,t.comm,t.job into pSal,pComm,pJob from xgj_test t where t.username=staffName;end QueryStaffInfo;*/// 我們可以看到該存過 4個參數 1個入參 3個出參String sql = "{call QueryStaffInfo(?,?,?,?)}";try {// 獲取連接conn = DBUtils.getConnection();// 通過連接獲取到CallableStatementcallableStatement = conn.prepareCall(sql);// 對于in 參數,需要賦值callableStatement.setString(1, "xiao");// 對于out 參數,需要聲明callableStatement.registerOutParameter(2, OracleTypes.NUMBER); // 第二個 ?callableStatement.registerOutParameter(3, OracleTypes.NUMBER);// 第三個 ?callableStatement.registerOutParameter(4, OracleTypes.VARCHAR);// 第四個 ?// 執行調用callableStatement.execute();// 取出結果int salary = callableStatement.getInt(2);int comm = callableStatement.getInt(3);String job = callableStatement.getString(3);System.out.println(salary + "\t" + comm + "\t" + job);} catch (SQLException e) {e.printStackTrace();}finally {DBUtils.cleanup(conn, callableStatement, null);}} }

在應用程序中訪問存儲函數

import java.sql.CallableStatement; import java.sql.Connection;import org.junit.Test;import com.turing.oracle.dbutil.DBUtils;import oracle.jdbc.OracleTypes;public class TestFuction {@Testpublic void callFuction(){//{?= call <procedure-name>[(<arg1>,<arg2>, ...)]}Connection conn = null;CallableStatement call = null;/*** create or replace function querySalaryInCome(staffName in varchar2)return number as--定義變量保存員工的工資和獎金pSalary xgj_test.sal%type;pComm xgj_test.comm%type;begin--查詢員工的工資和獎金select t.sal, t.comminto pSalary, pCommfrom xgj_test twhere t.username = staffName;--直接返回年薪return pSalary * 12 + nvl(pComm,0);end querySalaryInCome;*/String sql = "{?=call querySalaryInCome(?)}";try {// 獲取連接conn = DBUtils.getConnection();// 通過conn獲取CallableStatementcall = conn.prepareCall(sql);// out 參數,需要聲明call.registerOutParameter(1, OracleTypes.NUMBER);// in 參數,需要賦值call.setString(2, "gong");// 執行call.execute();// 取出返回值 第一個?的值double income = call.getDouble(1);System.out.println("該員工的年收入:" + income);} catch (Exception e) {e.printStackTrace();}finally {DBUtils.cleanup(conn, call, null);}}}

在out參數中訪問光標

在out參數中使用光標

我們之前拋出的兩個思考問題:

  • 查詢員工的所有信息–> out參數太多怎么辦?
  • 查詢某個部門中所有員工的信息–> out中返回集合?

我們可以通過返回Cursor的方式來實現。

在out參數中使用光標 的步驟:

  • 申明包結構
  • 包頭
  • 包體

包頭:

create or replace package MyPackage is-- Author : ADMINISTRATOR-- Created : 2016-6-4 18:10:42-- Purpose : -- 使用type關鍵字 is ref cursor說明是cursor類型type staffCursor is ref cursor;procedure queryStaffJob(pJob in xgj_test.job%type,jobStaffList out staffCursor);end MyPackage;

創建完包頭之后,創建包體,包體需要實現包頭中聲明的所有方法。

包體

create or replace package body MyPackage isprocedure queryStaffJob(pJob in xgj_test.job%type,jobStaffList out staffCursor)asbeginopen jobStaffList for select * from xgj_test t where t.job=pJob;end queryStaffJob;end MyPackage;

事實上,通過plsql工具創建包頭,編譯后,包體的框架就會自動的生成了。


在應用程序中訪問包下的存儲過程

在應用程序中訪問包下的存儲過程

在應用程序中訪問包下的存儲過程 ,需要帶包名

import java.sql.CallableStatement; import java.sql.Connection; import java.sql.ResultSet;import org.junit.Test;import com.turing.oracle.dbutil.DBUtils;import oracle.jdbc.OracleTypes; import oracle.jdbc.driver.OracleCallableStatement;public class TestCursor {@Testpublic void testCursor(){/*** * create or replace package MyPackage istype staffCursor is ref cursor;procedure queryStaffJob(pJob in xgj_test.job%type,jobStaffList out staffCursor);end MyPackage;*/String sql = "{call MyPackage.queryStaffJob(?,?)}" ;Connection conn = null;CallableStatement call = null ;ResultSet rs = null;try {// 獲取數據庫連接conn = DBUtils.getConnection();// 通過conn創建CallableStatemetcall = conn.prepareCall(sql);// in 參數 需要賦值call.setString(1, "Staff");// out 參數需要聲明call.registerOutParameter(2, OracleTypes.CURSOR);// 執行調用call.execute();// 獲取返回值rs = ((OracleCallableStatement)call).getCursor(2);while(rs.next()){// 取出值String username = rs.getString("username");double sal = rs.getDouble("sal");double comm = rs.getDouble("comm");System.out.println("username:" + username + "\t sal:" + sal + "\t comm:" + comm);}} catch (Exception e) {e.printStackTrace();}finally {DBUtils.cleanup(conn, call, rs);}}}

總結

以上是生活随笔為你收集整理的Oracle存储过程和自定义函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。