PL/SQL 训练11--包
--所谓包,就是把一组PL/SQL的代码元素组织在一个命名空间下。
--一种可以把程序或者其他的PL/SQL元素比如游标、类型、变量的组织结构在一起的结构(包括逻辑结构和物理结构)
--包提供了非常重要的、独一无二的功能,包括隐藏逻辑或者隐藏数据的功能,以及定义和操作“全局”或者
--会话持久数据的能力
--可以更容易地增强以及管理应用程序
--整体改善应用程序性能
--改善应用或者内置的薄弱环节
--代码重新编译的需求最小化
--包的演示
--包由两个代码块组成的:规范部分(必须的)和包体部分(可选的,但是一般都会提供)
--规范部分定义的是开发人员该如何使用这个包;包体部分包含罗列在规范部分的程序的实现代码以及还有其他必要的代码元素
- --先来看段代码
- create table employees(employee_id varchar2(32),first_name varchar2(100),last_name varchar2(100));
- procedure process_employee(in_id in employees.employee_id%type)
- is
- l_full_name varchar2(201);
- begin
- select e.last_name ||'_'||e.first_name
- into l_full_name
- from employees e
- where e.employee_id = in_id;
- end ;
- /
--这段代码有什么问题呢?硬编码、硬编码、硬编码
- --为什么不使用包呢?
- create or replace package employee_pkg is
- subtype full_name_t is varchar2(200);
- function fullname(in_last employees.last_name %type,
- in_first employees.first_name%type) return full_name_t;
- function fullname(in_id in employees.employee_id%type) return full_name_t;
- end employee_pkg;
- /
- --subtype 声明一个新的数据类型,如果要修改长度,很容易
- create or replace package body employee_pkg is
- function fullname(in_last employees.last_name %type,
- in_first employees.first_name%type) return full_name_t is
- begin
- return in_last || ',' || in_first;
- end fullname;
- function fullname(in_id in employees.employee_id%type) return full_name_t is
- l_full_name full_name_t;
- begin
- select fullname(e.last_name, e.first_name)
- into l_full_name
- from employees e
- where e.employee_id = in_id;
- return l_full_name;
- exception
- when no_data_found then
- return null;
- when too_many_rows then
- null;
- end fullname;
- end employee_pkg;
- /
---有关包一些概念
--隐藏信息:移除系统或者应用程序中的可见信息的实践活动
--公有和私有:公有代码是在包的规范部分定义的,任何对这个包有EXECUTE权限的模式都可以使用公有代码
--私有代码是在包的内部定义的并且只对包内可见
--构建包的时候,应该确定哪些元素是公有,哪些是私有的
--包规范:包的规范部分包含了可以被外部程序使用的所有公有元素的声明或者规范
--包体:包体包含了在包规范中所定义的元素的全部实现代码
--包体可以包含私有元素,这些元素不会出现在包声明中,也不能在包外使用
--初始化:可以通过初始化部分对包进行初始化
--会话持久性:持续会话生命周期
---外部、公有、私有
--构建包的规则
--包看起来是个很简单的结构,很容易掌握其语法和规则
- --包规范,先来看一个包,之前有一个购物车的实现,我们来看下包的规范部分
- create table ma_shopping_car(
- id_ma_shopping_car varchar2(32) default sys_guid() not null ,
- user_id varchar2(32),
- prouct_name varchar2(100),
- product_price number(13,2),
- product_num number
- );
- create or replace type ma_shopping_obj as object (
- id_ma_shopping_car varchar2(32) ,
- user_id varchar2(32),
- prouct_name varchar2(100),
- product_price number(13,2),
- product_num number
- );
- create or replace package ma_shopping_pkg is
- --常量
- c_page_num constant pls_integer := 10;
- --打印购物车
- procedure list_shopping_car(i_user_id in varchar2);
- procedure insert_shopping_car(v_product ma_shopping_obj);
- end ma_shopping_pkg ;
- /
--在包规范中可以声明差不多所有数据类型的元素,比如数字、异常、类型、集合。这些也叫做包级别数据
--一般来说,应该尽量避免在包的规范中声明变量,不过声明常量总是“安全的”
---不能在包规范中声明游标变量,游标变量不能做到会话范围内的持久化
--在包规范中可以声明任何的数据结构,比如集合类型,记录类型或者REF CURSOR 类型
--可以在包规范中声明一个过程和函数,但只能在包规范中包含程序的头部,头部必须用分号结尾
--可以在包规范中使用显示游标
--如果在包规范中声明了任意一个过程或者函数,或者声明一个没有查询语句的游标,必须提高一个包体来实现这些代码元素
--可以在包结尾的END语句之后可选的跟上一个包的名字作为标签
--包体
--包体部分包含了实现包规范所有需要的全部代码,包体并不总是必须的。
--当下面的条件为真时才需要包体
--包规范汇中包含了一个带有return子句的游标声明
--包规范中包含了过程或函数声明
--想通过包的初始化单元执行代码
- ---包规范本身并没有执行单元,只能在包体中实现
- create or replace package body ma_shopping_pkg is
- type shop_t is table of ma_shopping_obj index by ma_shopping_car.prouct_name%type;
- my_shopping_car shop_t; --私有变量
- procedure init_shopping_car(i_user_id in varchar2) is
- begin
- if my_shopping_car.count = 0 then
- for v_cur in (select r.id_ma_shopping_car,
- r.user_id,
- r.prouct_name,
- r.product_price,
- r.product_num
- from ma_shopping_car r
- where r.user_id = i_user_id) loop
- --赋值对象
- my_shopping_car(v_cur.prouct_name) := ma_shopping_obj(v_cur.id_ma_shopping_car,
- v_cur.user_id,
- v_cur.prouct_name,
- v_cur.product_price,
- v_cur.product_num);
- end loop;
- end if;
- end init_shopping_car;
- procedure list_shopping_car(i_user_id in varchar2) is
- v_index ma_shopping_car.prouct_name%type;
- begin
- if my_shopping_car.count = 0 then
- init_shopping_car(i_user_id);
- end if;
- v_index := my_shopping_car.first;
- while my_shopping_car.exists(v_index) loop
- dbms_output.put_line(my_shopping_car(v_index)
- .prouct_name || ',价格' ||
- my_shopping_car(v_index)
- .product_price || ',购买数量' ||
- my_shopping_car(v_index).product_num);
- v_index := my_shopping_car.next(v_index);
- end loop;
- end list_shopping_car;
- ---其它实现
- --购物车中数据持久化
- procedure insert_shopping_car(v_product in ma_shopping_obj) is
- begin
- insert into ma_shopping_car
- (id_ma_shopping_car,
- user_id,
- prouct_name,
- product_price,
- product_num)
- select nvl(v_product.id_ma_shopping_car, sys_guid()),
- v_product.user_id,
- v_product.prouct_name,
- v_product.product_price,
- v_product.product_num
- from dual;
- end insert_shopping_car;
- end ;
- /
- ---测试
- begin
- ma_shopping_pkg.insert_shopping_car(ma_shopping_obj(null,'test','IPAD',3200,5));
- ma_shopping_pkg.insert_shopping_car(ma_shopping_obj(null,'test','IPHONE',5000,3));
- ma_shopping_pkg.insert_shopping_car(ma_shopping_obj(null,'test','BOOK',300,2));
- end ;
- /
- select * from ma_shopping_car;
- begin
- ma_shopping_pkg.list_shopping_car('test');
- end ;
- /
--包体里可以有声明单元、执行单元、异常处理单元。
--在声明单元中就包括了在包规范中定义的任何一个游标和程序的完整实现
--也包括所有私有元素的定义。只要有一个初始化单元,声明单元可以为空
--包的执行单元也叫做初始化单元,可选的,当会话对这个包进行实例化时会执行这部分代码
--异常处理单元会处理初始化单元抛出的异常
--一个包体可以包括下面这些组合:只有一个声明单元;只有一个执行单元;
--同时有执行单元和异常处理单元;或者同时有声明单元、执行单元以及异常处理单元
--关于声明包级别数据结构的规则和约束同样适用于包体和包规范,比如不能声明一个游标变量
--可以在包体结尾的END语句后面选择性地使用包名标签
--包的初始化
--包可以包含能够持续在整个会话生命期内的数据结构
--当会话第一次使用某个包时,数据库都会对包初始化。
--初始化步骤
--初始化所有包级别的数据,比如数值变脸或者字符串常量
--用变量或者常量声明时所指定的缺省值给它们赋值
--执行初始化单元中的代码块,这个单元是专门为包的初始化设计的,作为前面没这些步骤的补充
--包的初始化单元由位于包结尾的BEGIN语句直到整个包体最后的END语句中所有语句组成
- create or replace package body ma_shopping_pkg is
- type shop_t is table of ma_shopping_obj index by ma_shopping_car.prouct_name%type;
- my_shopping_car shop_t; --私有变量
- function getName return varchar2;
- c_test varchar2(100) :=getName();
- function getName return varchar2 is
- begin
- dbms_output.put_line('oh hear');
- return 'hello';
- end getName;
- ---其它实现
- procedure init_shopping_car(i_user_id in varchar2) is
- begin
- if my_shopping_car.count = 0 then
- for v_cur in (select r.id_ma_shopping_car,
- r.user_id,
- r.prouct_name,
- r.product_price,
- r.product_num
- from ma_shopping_car r
- where r.user_id = i_user_id) loop
- --赋值对象
- my_shopping_car(v_cur.prouct_name) := ma_shopping_obj(v_cur.id_ma_shopping_car,
- v_cur.user_id,
- v_cur.prouct_name,
- v_cur.product_price,
- v_cur.product_num);
- end loop;
- end if;
- end init_shopping_car;
- procedure list_shopping_car(i_user_id in varchar2) is
- v_index ma_shopping_car.prouct_name%type;
- begin
- if my_shopping_car.count = 0 then
- init_shopping_car(i_user_id);
- end if;
- v_index := my_shopping_car.first;
- while my_shopping_car.exists(v_index) loop
- dbms_output.put_line(my_shopping_car(v_index)
- .prouct_name || ',价格' ||
- my_shopping_car(v_index)
- .product_price || ',购买数量' ||
- my_shopping_car(v_index).product_num);
- v_index := my_shopping_car.next(v_index);
- end loop;
- end list_shopping_car;
- --购物车中数据持久化
- procedure insert_shopping_car(v_product in ma_shopping_obj) is
- begin
- insert into ma_shopping_car
- (id_ma_shopping_car,
- user_id,
- prouct_name,
- product_price,
- product_num)
- select nvl(v_product.id_ma_shopping_car, sys_guid()),
- v_product.user_id,
- v_product.prouct_name,
- v_product.product_price,
- v_product.product_num
- from dual;
- end insert_shopping_car;
- begin
- dbms_output.put_line('这里正在进行初始化');
- end ma_shopping_pkg;
- /
- begin
- ma_shopping_pkg.list_shopping_car('test');
- end ;
- /
- begin
- ma_shopping_pkg.list_shopping_car('test');
- end ;
- /
--为什么要进行初始化
--执行复杂的初始化逻辑
--缓存静态的会话信息
--避免初始化时的意外情况
--初始化失败?
- create or replace package pkg_err is
- function get return varchar2;
- end pkg_err;
- /
- create or replace package body pkg_err is
- v varchar2(1) := 'abc';
- function get return varchar2 is
- begin
- return v;
- end get;
- begin
- dbms_output.put_line('oh,I am hear');
- exception
- when others then
- dbms_output.put_line('interesting,there is error');--这个异常只捕获声明单元的异常
- end pkg_err;
- /
- ---发生了什么?
- begin
- dbms_output.put_line(pkg_err.get);
- end ;
- /
- --再一次
- begin
- dbms_output.put_line(nvl(pkg_err.get,'noting'));
- end ;
- /
---使用包数据
--包数据是定义在包级别的变量和常量组成的,也就是不是在包的某个函数和过程中定义的
--包数据的作用范围:整个包
--会话持久性
---如果包数据是在包体中声明的,会话期间持久化,私有的,只能被包内部成员使用
--如果包数据是在包规范中声明的,则这个数据会在整个会话生命期内持久化
--可以被那些对这个包有EXECUTE权限的程序使用。
--如果在一个包过程中打开一个游标,这个游标会在整个会话生命期中一直保持这打开和可用的状态
--包变量可以跨越事务边界传递数据
---在一个ORACLE会话内全局可见
--包数据不能在多个会话之间共享使用
--全局公有数据:在包规范中声明的所有数据结构都属于全局公有的数据结构
--也就是位于包以外的程序都可以使用它们
---包游标
--可以在包中声明一个游标(显示游标),既可以在包体中声明也可以在包规范中声明。
--这个游标的状态会在整个会话中保持
--可以在一个程序里打开游标,在另外一个程序里提取数据,在第三个程序里关闭游标
--灵活但有可能导致问题
---声明包游标
--在包规范中声明一个显示游标,有两种方法
--1.在包规范中声明一个带查询语句的完整游标。和在一个局部PL/SQL块中声明游标完全一样
--2. 只声明一个游标的头部,不带有查询语句。这种方式下,查询是在包体中定义的
--对于第二种方式,只声明了游标头,必须在游标定义加上一个return子句
- --return语句只能利用数据库中表的%ROWTYPE属性定义的记录或者用户自定的记录类型
- create or replace package ma_shopping_pkg2 is
- CURSOR cur_my_car(i_user in ma_shopping_car.user_id%type) is
- select * from ma_shopping_car t where t.user_id = i_user;
- cursor cur_my_car1(i_user in ma_shopping_car.user_id%type) return ma_shopping_car%rowtype;
- type ma_shop_rec is record(
- product_name varchar2(100),
- total_price number
- );
- cursor cur_my_total(i_user in ma_shopping_car.user_id%type) return ma_shop_rec;
- end ma_shopping_pkg2;
- /
- create or replace package body ma_shopping_pkg2 is
- cursor cur_my_car1(i_user in ma_shopping_car.user_id%type) return ma_shopping_car%rowtype is
- select * from ma_shopping_car t where t.user_id = i_user;
- cursor cur_my_total(i_user in ma_shopping_car.user_id%type) return ma_shop_rec is
- select t.prouct_name, sum(t.product_num * t.product_price)
- from ma_shopping_car t
- where t.user_id = i_user
- group by t.prouct_name;
- end ma_shopping_pkg2;
- /
- ---使用包游标,在前面课程里,我们已经学习了游标,包游标的使用语法没什么特别的
- DECLARE
- v_car ma_shopping_car%rowtype;
- BEGIN
- open ma_shopping_pkg2.cur_my_car('test');
- loop
- exit when ma_shopping_pkg2.cur_my_car%notfound;
- fetch ma_shopping_pkg2.cur_my_car
- into v_car;
- dbms_output.put_line(v_car.prouct_name);
- end loop;
- close ma_shopping_pkg2.cur_my_car;
- END;
- /
- --示例中的游标是在包规范中声明的,所以游标的作用范围不局限于任何PL/SQL块,比如
- BEGIN
- open ma_shopping_pkg2.cur_my_car('test');
- END;
- /
- DECLARE
- v_car ma_shopping_car%rowtype;
- BEGIN
- loop
- exit when ma_shopping_pkg2.cur_my_car%notfound;
- fetch ma_shopping_pkg2.cur_my_car
- into v_car;
- dbms_output.put_line(v_car.prouct_name);
- end loop;
- END;
- /
- BEGIN
- close ma_shopping_pkg2.cur_my_car;
- END;
- /
---关于游标的持久化
--永远不要假设一个包游标已经关闭
--永远不要假设一个包游标是打开的
--确保每次使用完包游标后,总是显示的关闭它。就算在异常处理部分也要加上这个逻辑
--这样可以保证无论从哪个点退出程序,游标都会关闭
---包的串行化
--包数据有些缺陷
--可能导致无法预料的情况发生
--如果数据都存在包级别的结构中,程序就可能消耗大量的物理内存
--可以使用SERIALLY_REUSABLE编译指令对包标识成串行的可重用,包规范和包体都必须同时出现
--即对这种包的状态的生命周期可以从整个会话减少到对包的一个程序调用
- --示例
- create or replace package ma_shopping_pkg3 is
- pragma serially_reusable ;
- procedure fill_shopping_car;
- procedure list_shopping_car;
- end ma_shopping_pkg3 ;
- /
- create or replace package body ma_shopping_pkg3 is
- pragma serially_reusable;
- type shop_t is table of ma_shopping_car%rowtype index by varchar2(32);
- my_shopping_car shop_t;
- procedure fill_shopping_car is
- begin
- for v in (select * from ma_shopping_car) loop
- my_shopping_car(v.prouct_name) := v;
- end loop;
- end fill_shopping_car;
- procedure list_shopping_car is
- v_index ma_shopping_car.prouct_name%type;
- begin
- if my_shopping_car.count = 0 then
- dbms_output.put_line('nothing');
- else
- v_index := my_shopping_car.first;
- while my_shopping_car.exists(v_index) loop
- dbms_output.put_line(my_shopping_car(v_index)
- .prouct_name || ',价格' ||
- my_shopping_car(v_index)
- .product_price || ',购买数量' ||
- my_shopping_car(v_index).product_num);
- v_index := my_shopping_car.next(v_index);
- end loop;
- end if;
- end list_shopping_car;
- end ma_shopping_pkg3;
- /
- --两种不同的调用方式,看看发生了什么
- begin
- ma_shopping_pkg3.fill_shopping_car;
- ma_shopping_pkg3.list_shopping_car;
- end ;
- /
- begin
- ma_shopping_pkg3.fill_shopping_car;
- end ;
- /
- begin
- ma_shopping_pkg3.list_shopping_car;
- end ;
- /
- --何时使用包
- --封装数据操作
- --与其让开发人员自己写SQL语句,不如给这些语句提供一个接口。表API或者事务API
- create or replace package ma_shopping_pkg is
- --常量
- c_page_num constant pls_integer := 10;
- --打印购物车
- procedure list_shopping_car(i_user_id in varchar2);
- --获取购物车信息
- procedure init_shopping_car(i_user_id in varchar2);
- procedure insert_shopping_car(v_product ma_shopping_obj);
- function update_shopping_car(v_product ma_shopping_obj) return number;
- procedure save_shopping_car ;
- end ma_shopping_pkg ;
- /
- create or replace package body ma_shopping_pkg is
- type shop_t is table of ma_shopping_obj index by ma_shopping_car.prouct_name%type;
- my_shopping_car shop_t; --私有变量
- procedure list_shopping_car(i_user_id in varchar2) is
- v_index ma_shopping_car.prouct_name%type;
- begin
- if my_shopping_car.count = 0 then
- init_shopping_car(i_user_id);
- end if;
- v_index := my_shopping_car.first;
- while my_shopping_car.exists(v_index) loop
- dbms_output.put_line(my_shopping_car(v_index)
- .prouct_name || ',价格' ||
- my_shopping_car(v_index)
- .product_price || ',购买数量' ||
- my_shopping_car(v_index).product_num);
- v_index := my_shopping_car.next(v_index);
- end loop;
- end list_shopping_car;
- ---其它实现
- procedure init_shopping_car(i_user_id in varchar2) is
- begin
- if my_shopping_car.count = 0 then
- for v_cur in (select r.id_ma_shopping_car,
- r.user_id,
- r.prouct_name,
- r.product_price,
- r.product_num
- from ma_shopping_car r
- where r.user_id = i_user_id) loop
- --赋值对象
- my_shopping_car(v_cur.prouct_name) := ma_shopping_obj(v_cur.id_ma_shopping_car,
- v_cur.user_id,
- v_cur.prouct_name,
- v_cur.product_price,
- v_cur.product_num);
- end loop;
- end if;
- end init_shopping_car;
- --购物车中数据持久化
- procedure insert_shopping_car(v_product in ma_shopping_obj) is
- begin
- insert into ma_shopping_car
- (id_ma_shopping_car,
- user_id,
- prouct_name,
- product_price,
- product_num)
- select nvl(v_product.id_ma_shopping_car, sys_guid()),
- v_product.user_id,
- v_product.prouct_name,
- v_product.product_price,
- v_product.product_num
- from dual;
- end insert_shopping_car;
- function update_shopping_car(v_product ma_shopping_obj) return number is
- begin
- update ma_shopping_car r
- set r.prouct_name = v_product.prouct_name,
- r.product_price = v_product.product_price,
- r.product_num = v_product.product_num
- where r.id_ma_shopping_car = v_product.id_ma_shopping_car;
- return sql%rowcount;
- end update_shopping_car;
- procedure save_shopping_car is
- v_index ma_shopping_car.prouct_name%type;
- begin
- if my_shopping_car.count <> 0 then
- v_index := my_shopping_car.first;
- while my_shopping_car.exists(v_index) loop
- if update_shopping_car(my_shopping_car(v_index)) = 0 then
- insert_shopping_car(my_shopping_car(v_index));
- end if;
- end loop;
- end if;
- end;
- end ma_shopping_pkg;
- /
---避免对直接量的硬编码
--把常量放在包中,并给这些直接量一个名字,避免在每个程序中的硬编码。
--改善内置功能的可用性
--ORACLE自己的一些工具,比如UTL_FILE,还离期待的有所差距。基于这些工具构建我们自己的包
--可以尽可能地弥补这些问题
--把逻辑上相关的功能组织在一起
--如果有一堆过程和函数都是围绕着程序的某方面内容的,那么把它们放在一个包里
--更容易管理代码
--缓存会话的静态数据从而盖上应用程序性能
--利用包的持久化来缓存静态数据,可以改善应用程序的响应时间
------------------------------------------------------------------------------------------------
- 1 异常包
- CREATE OR REPLACE PACKAGE TEST1.exception_logs_pkg
- IS
- PROCEDURE exception_logs_p (
- i_option_users IN exception_logs.option_users%TYPE,
- i_method_name IN exception_logs.method_name%TYPE,
- i_exception_line IN exception_logs.exception_line%TYPE,
- i_exception_code IN exception_logs.exception_code%TYPE,
- i_exception_message IN exception_logs.exception_message%TYPE--i_exception_level IN exception_logs.exception_level%TYPE
- );
- END exception_logs_pkg;
- /
- CREATE OR REPLACE PACKAGE BODY TEST1.exception_logs_pkg
- IS
- /******************************************************************************
- NAME: exception_logs_pkg
- PURPOSE:
- REVISIONS:
- Ver Date Author Description
- --------- ---------- --------------- ------------------------------------
- 1.0 2016-03-08 hongquan 1. Created this package body.
- ******************************************************************************/
- PROCEDURE exception_logs_p (
- i_option_users IN exception_logs.option_users%TYPE,
- i_method_name IN exception_logs.method_name%TYPE,
- i_exception_line IN exception_logs.exception_line%TYPE,
- i_exception_code IN exception_logs.exception_code%TYPE,
- i_exception_message IN exception_logs.exception_message%TYPE--i_exception_level IN exception_logs.exception_level%TYPE
- )
- IS
- PRAGMA AUTONOMOUS_TRANSACTION;
- v_sysdate DATE DEFAULT SYSDATE;
- v_exception_level NUMBER DEFAULT 0;
- BEGIN
- BEGIN
- SELECT exception_level
- INTO v_exception_level
- FROM exception_level
- WHERE exception_code=i_exception_code;
- EXCEPTION
- WHEN OTHERS THEN
- v_exception_level:=3;
- END ;
- BEGIN
- INSERT INTO exception_logs (option_users,
- method_name,
- exception_time,
- exception_line,
- exception_code,
- exception_message,
- exception_level)
- VALUES (i_option_users,
- i_method_name,
- v_sysdate,
- i_exception_line,
- i_exception_code,
- i_exception_message,
- v_exception_level);
- COMMIT;
- EXCEPTION
- WHEN OTHERS
- THEN
- ROLLBACK;
- END;
- END;
- END exception_logs_pkg;
- /
- 2 购物车模块包
- CREATE OR REPLACE package TEST1.ma_shopping_pkg is
- --常量
- c_page_num constant pls_integer := 10;
- --打印购物车
- procedure list_shopping_car(i_user_id in varchar2);
- --获取购物车信息
- procedure init_shopping_car(i_user_id in varchar2);
- procedure insert_shopping_car(v_product ma_shopping_obj);
- function update_shopping_car(v_product ma_shopping_obj) return number;
- procedure save_shopping_car ;
- end ma_shopping_pkg ;
- /
- CREATE OR REPLACE package body TEST1.ma_shopping_pkg is
- type shop_t is table of ma_shopping_obj index by ma_shopping_car.prouct_name%type;
- my_shopping_car shop_t; --私有变量
- procedure list_shopping_car(i_user_id in varchar2) is
- v_index ma_shopping_car.prouct_name%type;
- begin
- if my_shopping_car.count = 0 then
- init_shopping_car(i_user_id);
- end if;
- v_index := my_shopping_car.first;
- while my_shopping_car.exists(v_index) loop
- dbms_output.put_line(my_shopping_car(v_index)
- .prouct_name || ',价格' ||
- my_shopping_car(v_index)
- .product_price || ',购买数量' ||
- my_shopping_car(v_index).product_num);
- v_index := my_shopping_car.next(v_index);
- end loop;
- end list_shopping_car;
- ---其它实现
- procedure init_shopping_car(i_user_id in varchar2) is
- begin
- if my_shopping_car.count = 0 then
- for v_cur in (select r.id_ma_shopping_car,
- r.user_id,
- r.prouct_name,
- r.product_price,
- r.product_num
- from ma_shopping_car r
- where r.user_id = i_user_id) loop
- --赋值对象
- my_shopping_car(v_cur.prouct_name) := ma_shopping_obj(v_cur.id_ma_shopping_car,
- v_cur.user_id,
- v_cur.prouct_name,
- v_cur.product_price,
- v_cur.product_num);
- end loop;
- end if;
- end init_shopping_car;
- --购物车中数据持久化
- procedure insert_shopping_car(v_product in ma_shopping_obj) is
- begin
- insert into ma_shopping_car
- (id_ma_shopping_car,
- user_id,
- prouct_name,
- product_price,
- product_num)
- select nvl(v_product.id_ma_shopping_car, sys_guid()),
- v_product.user_id,
- v_product.prouct_name,
- v_product.product_price,
- v_product.product_num
- from dual;
- end insert_shopping_car;
- function update_shopping_car(v_product ma_shopping_obj) return number is
- begin
- update ma_shopping_car r
- set r.prouct_name = v_product.prouct_name,
- r.product_price = v_product.product_price,
- r.product_num = v_product.product_num
- where r.id_ma_shopping_car = v_product.id_ma_shopping_car;
- return sql%rowcount;
- end update_shopping_car;
- procedure save_shopping_car is
- v_index ma_shopping_car.prouct_name%type;
- begin
- if my_shopping_car.count <> 0 then
- v_index := my_shopping_car.first;
- while my_shopping_car.exists(v_index) loop
- if update_shopping_car(my_shopping_car(v_index)) = 0 then
- insert_shopping_car(my_shopping_car(v_index));
- end if;
- end loop;
- end if;
- end;
- end ma_shopping_pkg;
- /
- 3 订单派工模块包
- create or replace package distribute_orders is
- function get_area_dealer(in_area varchar2) return varchar2 result_cache;
- procedure distribute_orders;
- end distribute_orders;
- /
- create or replace package body distribute_orders is
- type cache_t is table of order_area_dealer_config.deal_user%type index by varchar2(32);
- g_cache cache_t;
- function get_area_dealer(in_area varchar2) return varchar2 result_cache RELIES_ON(order_area_dealer_config) is
- v_dealer order_area_dealer_config.deal_user%type;
- begin
- if g_cache.exists(in_area) then
- v_dealer := g_cache(in_area);
- else
- select deal_user
- into v_dealer from order_area_dealer_config where distribution_area = in_area and rownum = 1;
- g_cache(in_area) := v_dealer;
- end if;
- return v_dealer;
- end get_area_dealer;
- procedure distribute_orders is
- cursor cur_ma_orders is
- select * from ma_orders where is_distributed = 'N';
- v_dealer order_area_dealer_config.deal_user%type;
- begin
- for v in cur_ma_orders loop
- v_dealer := get_area_dealer(v.distribution_area);
- insert into order_distribute
- (id_ma_orders, deal_user)
- values
- (v.id_ma_orders, v_dealer);
- update ma_orders t
- set t.is_distributed = 'Y'
- where t.id_ma_orders = v.id_ma_orders;
- end loop;
- commit;
- end;
- end distribute_orders;
- /
PL/SQL 训练11--包的更多相关文章
- Oracle数据库之开发PL/SQL子程序和包
Oracle数据库之开发PL/SQL子程序和包 PL/SQL块分为匿名块与命名块,命名块又包含子程序.包和触发器. 过程和函数统称为PL/SQL子程序,我们可以将商业逻辑.企业规则写成过程或函数保 ...
- PL/SQL重新编译包无反应案例2
在这篇"PL/SQL重新编译包无反应"里面介绍了编译包无反应的情况,今天又遇到一起案例, 在测试环境中,一个包的STATUS为INVALID,重新编译时,一直处于编译状态,检查发现 ...
- PL/SQL developer 11.0注册码
PL/SQL developer 11.0注册码:product key:lhsw85g33x4p7leqk63hy8q28ffxzzvbxlserial No:193085password:xs37 ...
- oracle 学习(五)pl/sql语言存储过程&包
首先搞清楚俩概念 存储过程(procedure)&程序包(package) 存储过程:数据库对象之一,可以理解为数据库的子程序,在客户端和服务器端可以直接调用它.触发器是与表直接关联的特殊存储 ...
- PL/SQL 训练13--plsql 优化
--数据缓存技术 --PGA和SGA---SGA:系统全局区域--PGA:Process Global Area是为每个连接到Oracle的用户进程保留的内存. ---PLSQL从PGA获取信息的速度 ...
- PL/SQL 训练03 --异常
--程序员在开发的时候,经常天真的认为这个世界是完美的,用户如同自己般聪明,总能按照自己设想的方式--操作系统输入数据.但残酷的事实告诉我们,这是不可能的事情,用户总会跟我们相反的方式操作系统--于是 ...
- 开发PL/SQL子程序和包及使用PL/SQL编写触发器、在JDBC中应用Oracle
1. 子程序的各个部分: 声明部分.可执行部分.异常处理部分(可选) 2.子程序的分类: A. 过程 - 执行某些操作 a. 创建过程的语法: CREATE [OR REPLACE] PROC ...
- PL/SQL重新编译包无反应
前几天碰到一个有趣的事情:早上同事执行一个包很久没有反应,就中断了执行,发邮件让我帮忙查看具体情况,我用PL/SQL Developer登录后,找到这个包的过程中发现这个包的图标有红色叉叉,也就是说这 ...
- PL/SQL 包头和包体
包用于逻辑组合相关的过程和函数,它由包规范和包体两部分组成,包规范用于定义公用的常量 变量,过程和函数,在SQL*PLUS中建立包规范可以使用CREATE PACKAGE命令. 实例如下: CREAT ...
- 二十三、oracle pl/sql分类三 包
包用于在逻辑上组合过程和函数,它由包规范和包体两部分组成.1).我们可以使用create package命令来创建包,如:i.创建一个包sp_packageii.声明该包有一个过程update_sal ...
随机推荐
- 报错如HTTP Status 404 - /ssh_crm/jsp/linkman/add.jsp/
明显是写错了, HTTP Status 404 - /ssh_crm/jsp/linkman/add.jsp/ 应该改成 HTTP Status 404 - /ssh_crm/jsp/linkman/ ...
- 用 LoadLibraryExW 函数测试加载 dll (CSharp、Windows)
效果如下: $ llbtest "E:\Developer\emgucv-windesktop 3.3.0.2824\libs\x64" LoadLibraryExW PATH: ...
- B树, B-树,B+树,和B*树的区别
B树: B树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中: 否则,如果查询关键字比结点关键字小,就进入左儿子:如果比结点关键字大,就进入 右儿子:如果左儿子或右儿子的指针为空, ...
- Chrome浏览器导出数字证书
1.F12打开开发者工具,选中"Security"面板-->找到"View certificate",点击 2.选中“详细信息”面板-->复制到文件
- HDU 1561 The more, The Better(树形DP+01背包)
The more, The Better Time Limit : 6000/2000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other ...
- 利用 innodb_force_recovery 解决MySQL服务器crash无法重启问题
背景 MySQL服务器因为磁盘阵列损坏机器crash,重启MySQL服务时 报如下错误: InnoDB: Reading tablespace information from the .i ...
- Agilent RF fundamentals (3)- TX and RX
1Create carrier:谐振器,如433.92Mhz LC谐振 (频偏控制) 2Add data to carrier 加载数据 3Amplify to broadcast :放大器,如NPN ...
- New Concept English three (36)
21 54 We are less credulous than we used to be. In the nineteenth century, a novelist would bring hi ...
- Arcgis andoid开发之应用百度地图接口实现精准定位与显示
怀着激动.兴奋的心情,在这个漫天柳絮的季节写下了这片博文,为什么呢,因为困扰我很久的一个技术性的问题得到了解决,发次博文,供大家参观.学习,同时,也以慰藉我长期困扰的心情,好了,废话不再,言归正传,看 ...
- Django 碎片集合
命令行创建Django项目 熟记建立django命令:django-admin startproject xx (start project) 目录介绍 manage.py 文件是用来管理文件 ...