当前位置: 首页 > backend >正文

Oracle--存储过程

  前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除

存储过程

命名的PL/SQL块可以被独立编译并存储在数据库中,Oracle提供了4种可以存储的PL/SQL块,及过程、函数、触发器和包

存储过程是命名的PL/SQL块,可有无参数、输入参数、输出参数或既输入又输出的参数,但通常无返回值,它保存在数据库中,不能被SQL语句直接执行或调用,需通过EXECUTE命令或在PL/SQL块内部调用,因是编译好的代码,执行效率高。

一、创建存储过程

创建存储过程与编写普通PL/SQL块虽都有声明、执行和异常处理三部分,但细节有别:存储过程需用PROCEDURE关键字后跟过程名和参数列表,且用CREATE或REPLACE关键字而非DECLARE,其格式:

 CREATE [OR REPLACE] PROCEDURE pro_name [(parameter1[,parameter2...)] IS|ASBEGINplsql_sentences;[EXCEPTION][dowith _ sentences;]END [pro_namel;

二、存储过程的参数

存储过程通过参数实现单元输入和输出数据,参数模式有IN(输入)、OUT(输出)和IN OUT(输入输出)三种,这增强了其灵活性,区别于前面创建的无参数的简单存储过程。

1、IN模式参数

IN模式参数是一种输入类型的参数,参数值由调用方传入,并且只能被存储过程读取。这种参数模式是最常用的,也是默认的参数模式,关键字IN位于参数名称之后。

 --创建一个存储过程,并定义3个IN模式的变量,然后将这3个变量的值插入dept表中create or replace procedure insert_dept(num_deptno in number,           --定义IN模式的变量,它存储部门编号var_dname in varchar2,          --定义IN模式的变量,它存储部门名称var_loc in varchar2) is         --定义IN模式的变量,它存储部门位置begin insert into deptvalues(num_deptno,var_dname,var_loc);commit;     end insert_dept;/

上述代码成功创建了一个存储过程,需注意参数类型不能指定长度。调用或执行IN模式存储过程时,用户需传递若干参数值,以确保执行部分(BEGIN部分)有具体数值参与数据操作。向存储过程传入参数有以下3种方式。

1.1、指定名称传递

指定名称传递是在向存储过程传递参数时,需明确写出参数名称,左侧是参数名,中间用“=>”连接,右侧是参数值,其语法:

 pro_name(paramater1=>value1[,paramater2=>value2]...)

参数名称与存储过程中定义的参数顺序无关

 --示例:在PL/SQL块中调用存储过程insert_dept,然后使用"指定名称"的方式传入参数值,最后执行当前的PL/SQL块begininsert_dept(var_dname=>'财务部',var_loc=>'烟台',num_deptn=>15);end;/
1.2、按位置传递

指定名称传递参数虽然直观易读,但当参数过多时会使代码冗长,反而不利于阅读。此时可以采用按位置传递参数的方式,这种方式要求提供的参数值顺序必须与存储过程中定义的参数顺序相同

 --示例:在PL/SQL块中调用存储过程insert_dept,然后使用"按位置传递"的方式传入参数值,最后执行begininsert_into(11,'工程部','威海');end;/

当参数过多难以记住顺序和类型时,可通过DESC命令查看存储过程的参数定义信息,包括参数名、定义顺序、类型和模式等。

1.3、混合方式传递

混合方式就是将前两种方式结合到一起,可以兼顾二者的优点

 --示例:使用混合方式传递exec insert_dept(12,var_loc=>'济南',var_dname=>'测试部');

注意:在某个位置使用指定名称传递方式传入参数值后,其后面的参数值也要使用指定名称传递,因为指定名称传递方式有可能已经破坏了参数原始的定义顺序

2、OUT模式参数

OUT模式参数是一种输出类型的参数,表示这个参数在存储过程中已经被赋值,并且这个参数值可以被传递到当前存储过程以外的环境中,关键字OUT位于参数名称之后

 --创建一个存储过程,要求定义两个OUT模式的字符类型的参数,将在dept表中检索到的一行部门信息存储到这两个参数中create or replace procedure select_dept(num_deptno in number,var_dname out dept.dname%type,var_loc out dept.loc%type) isbeginselect dname,locinto var_dname,var_locfrom deptwhere deptno = num_deptno;      --检索某个部门编号的部门信息exceptionwhen no_data_found thendbms_output.put_line('该部门编号不存在');end select_dept;/

在上述存储过程(即select dept)中,定义了两个OUT参数。由于存储过程通过OUT参数返回值,所以在调用或执行该存储过程时,需要定义变量来保存这两个OUT参数的值。

2.1、在PL/SQL块中调用OUT模式的存储过程

这种方式需要在PL/SQL块的DECLARE部分定义与存储过程中OUT参数兼容的若干变量

 --在PL/SQL块中声明若干变量,然后调用select_dept存储过程,并将定义的变量传入该存储过程中,以便接收OUT参数的返回值set serveroutput ondeclarevar_dname dept.dname%type;  --声明变量,对应过程中的OUT模式的var_dnamevar_loc dept.loc%type;      --声明变量,对应过程中的OUT模式的var_locbeginselect_dept(77,var_dname,var_loc);dbms_output.put_line(var_dname||'位于:'||var_loc);    --输出部门信息end;/
2.2、使用EXEC命令执行OUT模式的存储过程

当使用EXEC命令时,雲要在SQL*Plus环境中使用VARIABLE关键字声明两个变量,用以存储OUT参数的返回值

 --使用VARIABLE关键字声明两个变量,分别存储部门名称和位置信息,然后使用EXEC命令执行存储过程,并传入声明的两个变量来接受OUT参数的返回值variable var_dname varchar2(50);variable var_loc varcahr2(50);exec select_dept(11,:var_dname,:var_loc);​--使用SELECT语句检索并输出变量var_dname和var_loc的值select :var_dname,:var_loc from dual;

注意:如果在存储过程中声明了OUT模式的参数,则在执行存储过程时,必须为OUT参数提供变量,以便接收OUT参数的返回值;否则,程序执行后将出现错误

3、IN OUT模式参数

在执行存储过程时,IN参数只能提供数据,不能被修改;OUT参数只能被赋值,不能提供数据;而IN OUT参数兼具两者特点,既能传入值也能返回值

 --创建一个存储过程,其中定义一个IN OUT参数,该存储过程用来计算这个参数的平方或平方根:create or replace procedure pro_square(num in out number,flag in boolean) isi int := 2;beginif flag thennum := power(num,i)elsenum :=sqrt(num);end ifend;

在上述存储过程中,定义了一个IN OUT参数,它在存储过程被调用时接收一个数值,之后与另一个IN参数配合来判断执行的运算方式(平方或平方根),最终将计算结果(平方或平方根的值)保存到该IN OUT参数中。

 --调用存储过程pro_square,计算某个数的平方或平方根set serverout ondeclarevar_number number;      --存储要进行运行的值和运行后的结果var_temp number;        --存储要进行运算的值boo_flag boolen;        --平方或平方根的逻辑标记beginvar_temp :=9;           --赋值变量var_number :=var_temp;boo_flag := false;pro_square(var_number,boo_flag);    --调用存储过程if boo_flag thendbms_output.put_line(var_temp ||'的平方是:'||var_number);elsedbms_output.put_line(var_temp ||'的平方根是:'||var_number);end if;end;/

三、IN参数的默认值

IN参数的值是在调用存储过程中传入的,Oracle支持在声明IN参数时为其初始化默认值。如果在调用存储过程时未传入值,存储过程就会使用默认值进行操作。

 --创建一个存储过程,定义3个IN参数,并将其中的两个参数各设置一个初始默认值,然后将这3个参数的值插入dept表中create or replace procedure insert_dept(num_deptno in number,var_dname in varchar2 default '行政部',var_loc in varchar2 defailt '青岛') isbegininsert into dept values(num_deptno,var_dname,var_loc);end;

在上述存储过程中,IN参数var_dname和var_loc都有默认值。因此,在调用insert_dept存储过程时,可以选择不传入值,直接使用其默认值(当然也可以传入值)。建议使用“指定名称传递”的方式传值,这样可以避免因参数顺序不固定而导致的混乱。

 --在PL/SQL块中调用insert_dept存储过程,并且只向该存储过程中传入两个参数值set serverout ondeclarerow_dept dept%rowtype;      --定义行变量,与dept表的一行类型相同begininsert_dept(57,var_loc=>'太原');  --调用insert_dept存储过程,传入参数commit;                         --提交数据库select * into row_dept from dept where deptno=57;dbms_output.put_line('部门名称是:《'||row_dept.dname||'》,位置是:《'||row_dept.loc||'》');end;/

四、删除存储过程

当一个过程不再被需要时,要将此过程从内存中删除,以释放相应的内存空间,代码如下:

 DROP PROCEDURE count_num;

删除存储过程insert dept,代码如下

 DROP PROCEDURE insert_dept;

当一个存储过程已经过时,想重新定义时,不必先删除再创建,只需在CREATE语句后面加上OR REPLACE关键字即可:

 CREATE OR REPLACE PROCEDURE count_num

五、函数

函数通常用于计算并返回一个值,可将常用的计算或功能封装成函数。函数调用是表达式的一部分,而过程调用是一条PL/SQL语句。二者在创建形式上类似,都是编译后存储在内存中供用户使用。不过,调用函数时需要通过表达式,而调用过程只需使用过程名。此外,函数必须有一个返回值,而过程没有返回值。

1、创建函数

函数的创建语法与存储过程类似,是一种存储在数据库中的命名程序块。它可以接收零个或多个输入参数,但必须有返回值(这是与存储过程的不同之处)。定义函数格式:

 CREATE  [OR REPLACE] FUNCTION fun_name[(parameter1[,parameter2]...) RETURN data_type IS [inner_variable]BEGINplsql sentence;[EXCEPTION][dowith _ sentences;]END [fun_name];

由于函数有返回值,因此在函数主体部分(即BEGIN部分)必须使用返回语句返回函数值,并且要求返回值的类型要与函数声明时的返回值类型(即data_type)相同

 --定义一个函数,用于计算emp表中指定部门的平均工资create or replace function get_avg_pay(num_deptno number) return number isnum_avg_pay number;     --保存平均工资的内部变量beginselect avg(sal) into num_avg_pay from emp where deptno=num_deptno;return(round(num_avg_pay,2));   --返回平均工资exceptionwhen no_data_found then     --若部门编号不存在dbms_output.put_line('该部门编号不存在')return(0);end;

2、调用函数

函数声明时所定义的参数成为形式参数,应用程序调用时为函数传递的参数称为实际参数。实际参数和形式参数之间的数据传递有两种方法:传址法和传值法

调用函数和调用过程有所不同,需要一个变量来保存返回的值,这样函数就组成了表达式的一部分。因此不能像调用过程那样独立地调用函数。

3、删除函数

对于不再使用的函数,可以使用DROP FUNCTION语句进行删除,语法如下:

 DROP FUNCTION <function_name>;

六、触发器

触发器是一种特殊的存储过程,它定义了在数据库相关事件(如INSERT、UPDATE、CREATE等)发生时应执行的功能代码块,通常用于管理复杂的完整性约束、监控表的修改、通知其他程序,甚至实现数据审计功能。

1、触发器简介

触发器是通过触发事件来执行的,与存储过程由用户或应用程序调用不同。触发事件包括执行DML语句(INSERT、UPDATE、DELETE)、执行DDL语句(CREATE、ALTER、DROP)、引发数据库系统事件(如启动、退出、异常错误)以及引发用户事件(如登录、退出数据库操作),这些操作都能引起触发器运行。其格式:

 CREATE [OR REPLACE] TRIGGER tri_name[BEFORE | AFTER | INSTEAD OF] tri_eventON table_name | view_name | user_name | db_name[FOR EACH ROW [WHEN tri_condition]BEGINplsql_sentences;END tri_name;
  • TRIGGER:创建触发器的关键字,类似于存储过程的PROCEDURE。
  • 触发时机的关键字有BEFORE(执行DML操作前触发,便于回滚或实现业务规则)、AFTER(DML操作后触发,便于记录操作或事后处理)和INSTEAD OF(替代触发器)。
  • ON用于指定操作的数据表、视图、用户模式或数据库,当对它们执行操作时触发器会运行。
  • FOR EACH ROW表示行级触发器,每行数据操作都会触发;否则为语句级触发器,无论影响多少行只执行一次。
  • tri_name是触发器名称,可通过OR REPLACE覆盖同名旧触发器。
  • trig_event是触发事件,如INSERT、UPDATE、DELETE等。
  • table_name|view_name|user_name|dbname分别表示操作对象。WHEN condition是触发条件子句,只有条件为TRUE时,遇到触发事件才会执行触发器。
  • plsql_sentences是实现触发器功能的主体代码

Oracle支持的触发器分为五种类型

  • 行级触发器,对每一行数据操作都会触发;
  • 语句级触发器,无论影响多少行,只执行一次;
  • 替换触发器,定义在视图上,替代实际语句;
  • 用户事件触发器,与DDL操作或用户登录、退出等事件相关;
  • 系统事件触发器,在Oracle系统事件(如实例启动与关闭)中触发。

2、语句级触发器

语句级触发器,是针对一条DML语句引起的触发器执行。在语句级触发器中,不使用FOR EACH ROW子句,也就是说无论数据操作影响多少行,触发器都只会执行一次。

在scot模式下,为了监控dept表的各种操作,需要创建一个日志表deptlog,用于存储对dept表的操作信息,如操作种类(插入、修改、删除)和操作时间。在scot模式下创建deptlog表,并定义两个字段分别存储操作种类和操作日期,代码:

 create table dept_log(operate_tag varchar2(10),       --定义字段,存储操作种类信息operate_time date               --定义字段,存储操作日期);
 --创建一个触发器tii_dept,该触发器在INSERT、UPDATE和DELETE事件下都可以被触发,操作的数据对象是dept表,并且在触发器执行时输出对dept所做的具体操作,代码如下:create or replace trigger tri_deptbefore insert or update or deleteon dept     --创建触发器,当dept表发生插入、修改、删除操作时,将引起该触发器执行declarevar_tag varchar2(10);beginif inserting thenvar_tag = '插入';elsif updating thenvar_tag = '修改';elsif deleting thenvar_tag = '删除';end if;insert into dept_logvalues(var_tag,sysdate);end tri_dept;/
 /*在数据表dept中实现插入、修改、删除3种操作,以便引起触发器tri_dept的执行,代码如下:*/insert into dept values(55,'业务部’'上海');update dept set loc='杭州' where deptno=55;delete from dept where deptno=55;commit;select * from dept_log;

3、行级触发器

行级触发器会针对DML操作所影响的每一行数据都执行一次触发器,创建这种触发器时,必须在语法中使用FOR EACH ROW这个选项;使用行级触发器的一个典型应用就是给数据表生成主键值。

 --首先创建一个带有主键列的数据表create table goods(id int primary key,good_name varchar2(50));

为了给goods表的id列生成不能重复的有序值,这里需要创建一个序列,使用CREATE SEQUENCE语句创建一个序列,命名为seq_id:

 create sequence seq_id;

上述代码创建了序列seqid,用户可在PL/SQL程序中调用其NEXTVAL属性获取有序数值,这些数值可作为goods表的主键值。接下来创建一个行级触发器,当向goods表插入数据时触发,并在触发器主体中设置goods表中id列的值,代码:

 create or replace trigger tri_insert_goodbefore insert   on goods        --关于goods数据表,在向其插入新记录之前,引起该触发器的运行for each row    --创建行级触发器beginselect seg_id.nextvalinto :new.idfrom dual;      --从序列中生成一个新的数值,赋值给当前插入行的id列

在行级触发器中,可通过“列标识符”访问受操作影响的数据行,分为“原值标识符”和“新值标识符”。原值标识符(如::old.column_name)用于标识列的原始值,常用于UPDATE和DELETE语句,因为INSERT语句中插入的行无原始值;新值标识符(如::new.column_name)用于标识列的新值,常用于INSERT和UPDATE语句,因为DELETE语句中删除的行无法产生新值

 --向goods表中插入两条记录,其中一条记录不指定id列的值,由序列seq_id来产生;另一条记录指定id的值insert into goods(good_name) values('香蕉');insert into goods(id,good_name) values(9,'柚子');​commit;select * from goods;

无论是否指定id列的值,数据插入都能成功。即使第二次插入时指定id值为9,也无效。因为在触发器中,序列seqid的NEXTVAL属性值被赋给:new.id列标识符,而:new.id就是当前插入行的id列值。NEXTVAL属性值是连续的,不受手动指定值的影响。

4、替换触发器

替换触发器(INSTEAD OF触发器)的“触发时机”关键字是INSTEAD OF,与BEFORE或AFTER不同。它定义在视图上,而非表上。由于视图是多张基表连接的逻辑结构,通常不允许DML操作(INSERT、UPDATE、DELETE)。但为视图编写替换触发器后,对视图的DML操作会变成执行触发器中的PL/SQL块,从而通过触发器代码对基表进行操作。

 --创建一个检索员工信息的视图create view view_emp_deptas select empno,ename,dept.deptno,dname,job,hiredatefrom emp,deptwhere emp.deptno = dept.deptno;--尝试向view_emp_dept视图中插入数据,会提示“ORA-01776:无法通过联接视图修改多个基表”;​--创建一个关于view_emp_dept视图的替换触发器,在该触发器的主体中实现向emp表和dept表中插入两行相互关联的数据create or replace trigger tri_insert viewinstead of inserton view_emp_dept    --创建一个关于view_emp_dept视图的替换触发器for each row        --是行级视图declarerow_dept number;beginSELECT count(*) INTO row_dept FROM dept WHERE deptno = :new.deptno;--检索指定部门编号的记录行if row_dept =0 then     --判断是否存在该部门编号的记录insert into dept(deptno,dname)values(:new.deptno,:new.dname);     --向dept表中插入数据end if;insert into emp(empno,ename,deptno,job,hiredate) values(:new.empno,:new.ename,:new.deptno,:new.job,:new.hiredate); --向emp表中插入数据end tri_insert_view;/

在上述触发器的主体代码中,如果新插入行的部门编号(deptno)不在dept表中,则首先向dept表中插入关于新部门编号的数据行,然后再向emp表中插入记录行,这是因为emp表的外键值(emp.deptno)是dept表的主键值(dept.deptno)。

成功创建触发器ti_insert_view之后,在向view_emp_dept视图中插入数据时,Orace就不会产生错误信息,而是引起触发器ti_inset_view的运行,从而实现向emp表和dept表中插入两行数据

 --向视图view_emp_dept中插入一条记录,然后检索插入的记录行insert into view_emp_dept (empno,ename,deptno,dname,iob,hiredate) values (7777,'小明',99,'测试部’,'测试工程师',sysdate)--查询deptno=99的数据select * from dept where deptno=99;--查询empno=7777的数据select * from emp where empno=7777;

dept表之前是没有部门编码deptno=99的记录的,触发器中的程序向dept表中插入deptno=99的数据,然后又向emp表中插入一条记录,

5、用户事件触发器

用户事件触发器是因进行DDL操作或用户登录、退出等操作而引起运行的一种触发器,常见引起该类型触发器运行的用户事件包括CREATE、ALTER、DROP、ANALYZE、COMMENT、GRANT、REVOKE、RENAME、TRUNCATE、SUSPEND、LOGON和LOGOFF等。

 --使用CREATE TABLE语句创建一个日志信息表,该表保存的日志信息句括数据对象、数据对象类型、操作行为、操作用户和操作日期等create table ddl_oper_log(db_obj_name varchar2(20),   --数据对象名称db_obj_type varchar2(20),   --对象类型oper_action varchar2(20),   --具体dd1行为oper_user varchar2(20),     --操作用户oper_date date              --操作日期  );

创建一个关于scot用户的DDL操作(这里包括CREATE、ALTER和DROP)的触发器,然后将DDL操作的相关信息插入ddl_oper_log日志表中

 create or replace trigger tri_ddl_operbefore create or alter or dropon scott.schema     --在scott模式下,在创建、修改、删除数据对象之前将引发该触发器运行begininsert into ddl_oper_log values(ora_dict_obj_name,          --操作的数据对象名称ora_dict_obj_type,          --对象类型ora_sysevent,               --系统事件名称ora_login_user,             --登录用户sysdate);end;/​

通过上述4个事件属性值和svsdate系统属性就可以将scot用户的DDL操作信息获取出来,然后再把这些信息保存到ddloperlog日志表中。

 --首先创建一张数据表和一个视图,然后删除视图和修改数据表,最后使用SELECT语句查看ddl_oper_log日志表中的DDL操作信息--创建tb_test表create table tb_test(id number);--创建view_test视图create view view_test as select empno,ename from emp;--修改tb_test表alter table tb_test add(name varchar2(10));--删除视图view_testdrop view view_test;--查询ddl_oper_log表select * from ddl_oper_1og;

6、删除触发器

当一个触发器不再使用时,要从内存中删除它

 --删除名为tri_dept触发器DROP TRIGGER tri_dept;

当一个触发器已经过时,想重新定义时,不必先删除再创建,只需在CREATE语句后面加上OR REPLACE关键字即可

 CREATE OR REPLACE TRIGGER my_trigger;

七、程序包

程序包由PL/SQL程序元素(如变量、类型)和匿名PL/SQL块(如游标)、命名PL/SQL块(如存储过程和函数)组成,可整体加载到内存中,加快访问速度。例如,PL/SQL中使用DBMS_OUTPUT.PUT_LINE语句,DBMS_OUTPUT是程序包,PUT_LINE是其中的存储过程。程序包通常由规范和包主体组成。

1、程序包的规范

程序包规范规定了在程序包中可以使用的变量、类型、游标和子程序(指各种命名的PL/SQL块)。需要注意的是,程序包规范必须在包主体之前创建。其语法:

 CREATE [OR REPLACE ] PACKAGE pack_name IS [declare _variable];   --规范内声明的变量[declare _type];            --规范内声明的类型[declare _cursor];          --规范内声明的游标[declare _function];        --规范内声明的函数[declare _procedure];       --规范内声明的存储过程END [pack_name];
 --创建一个程序包规范,首先在该程序包中声明一个可以获取指定部门的平均工资的函数,然后声明一个可以实现按照指定比例上调指定职务的工资的存储过程,代码如下:create or replace package pack_emp isfunction fun_avg_sal(num_deptno number) return number;      --获取指定部门的平均工资procedure pro_regulate_sal(var_job varchar2,num_proportion number);--按照指定比例上调指定职务的工资end pack emp;/

从上述代码中可以看到,在规范中声明的函数和存储过程只有头部的声明,而没有函数体和存储过程主体。

注意:只定义了规范的程序包还不可以被使用,此时如果在PL/SQL块中通过程序包的名称来调用其中的函数或存储过程,则Oracle将会产生错误提示

2、程序包的主体

程序包主体包含规范中声明的游标、过程和函数的实现代码,还可以声明内部变量。程序包主体的名称必须与规范名称相同,以便Oracle将二者结合成完整的程序包并编译。实现函数或存储过程主体时,可将每个函数或存储过程作为独立的PL/SQL块处理。与创建规范不同,创建程序包主体使用CREATE PACKAGE BODY语句,而不是CREATE PACKAGE语句。创建程序包主体的代码如下

 CREATE [OR REPLACE]PACKAGE BODY pack_name IS    --pack_name程序主体[inner_variable]        --程序包主体内部变量[cursor_body]           --游标主体[function_title]        --从规范中引入的函数头部声明{BEGINfun_plsq1;          --PL/SQL语句,函数功能实现[EXCEPTION][dowith _ sentences;]   --异常处理语句END [fun_name]}         --函数名称[procedure_title]       --从规范中引入的存储过程的头部声明{BEGINpro_plsql;          --PL/SQL语句,存储过程功能实现[EXCEPTION][dowith _ sentences;]END [pro_name]}         --存储过程名称...END [pack_name];

创建程序包pack_emp的主体,在该主体中实现与规范中声明的函数和存储过程对应:

 create or replace package body pack_emp isfunction fun_avg_sal(num_deptno number) return number isnum_avg_sal number;beginselect avg(sal)into num_avg_salfrom empwhere deptno = num_deptno;return(num_avg_sal);exceptionwhen no_data_found thendbms_output.put_line('该部门编号不存在员工记录');return 0;end fun_avg_sal;procedure pro_regulate_sal(var_job varchar2,num_proportion number) isbeginupdate empset sal = sal*(1+num_proportion)where job = var_job;    --为指定的职务调整工资end pro_regulate_sal;end pack_emp;

创建了程序包的规范和主体后,就可以像普通的存储过程和函数一样实施调用了

 --创建一个匿名的PL/SQL块,通过程序包pack_emp调用其中的函数fun_avg_sal和存储过程pro_regulate_sal,并输出函数的返回结果set serveroutput on​declarenum_deptno emp.deptno%type;var_job emp.job%type;num_avg_sal emp.sal%type;num_proportion number;beginnum_deptno:=10;num_avg_sal:=pack_emp.fun_avg_sal(num_deptno);dbms_output.put_line(num_deptno||'号部门的平均工资是:'||num_avg_sal);var_job:='SALESMAN';num_proportion:=0.1;pack_emp.pro_regulate_sal(var_job,num_proportion);end;/

3、删除程序包

Oracle包的删除可以使用以下SQL语句进行:

 DROP PACKAGE [schema.]package_name;

删除包体之前,需要先确保该包不再使用或被其它包体调用。最好的方法是在运行删除操作前,首先查找其它包体是否调用了该包体,并手动删除这些引用。可以使用以下SQL语句查找public synonyms:

 SELECT DISTINCT TEXTfrom DBA_DEPENDENCIESWHERE TYPE = ‘PACKAGE BODY’and REFERENCED_NAME = ‘Package_name’;

假设上述SQL查询没有显示任何结果,则可以执行删除包体操作

学习永无止境,让我们共同进步!!

http://www.xdnf.cn/news/1101.html

相关文章:

  • mybatis mapper.xml中使用枚举
  • Mysql 读写分离(3)之 schema.xml基本配置
  • 简化K8S部署流程:通过Apisix实现蓝绿发布策略详解(上)
  • 物联网 (IoT) 安全简介
  • 《开源大模型选型全攻略:开启智能应用新征程》
  • Ubuntu 上安装 Conda
  • Spark-Streaming核心编程
  • 深度剖析神经网络:从基础原理到面试要点(二)
  • 游戏引擎学习第239天:通过 OpenGL 渲染游戏
  • 三餐四季、灯火阑珊
  • Oracle DBA 高效运维指南:高频实用 SQL 大全
  • 极狐GitLab 项目功能和权限解读
  • 大数据学习(112)-HIVE中的窗口函数
  • Cursor这类编程Agent软件的模型架构与工作流程
  • Flink介绍——实时计算核心论文之Dataflow论文详解
  • OpenCV物体计数示例
  • Go语言和Python 3的协程对比
  • Spark-Streaming
  • Linux kernel signal原理(下)- aarch64架构sigreturn流程
  • Spring Boot 主模块 spring-boot 核心技术解析:从启动类到内嵌容器的无缝支持
  • dify工作流之text-2-e-sql,大模型写sql并执行
  • 深入理解 Spring @Configuration 注解
  • SpringBoot原生实现分布式MapReduce计算
  • Java高频面试之并发编程-05
  • 新能源汽车可视化大屏系统毕业设计
  • Node.js 模块导入的基本流程
  • 【Harmony】常用工具类封装
  • Jupyter Notebook 中切换/使用 conda 虚拟环境的方式(解决jupyter notebook 环境默认在base下面的问题)
  • Python爬虫从入门到实战详细版教程Char01:爬虫基础与核心技术
  • 【网络】代理服务器收尾及高级IO