Oracle Class7. 异常和游标管理

------------------------2013-5-18------------------------
异常
raise_application_error:错误编号必须介于-20000和-20999之间
错误消息的长度可长达2048个字节。

游标类型
静态游标
  隐式游标 sql%found  sql%rowcount
  显式游标 cur_xxx%found
ref游标

游标属性
  %notfound
  %found
  %rowcount
  %isopen
控制显示游标
  open
  fetch
  close

循环游标 显式游标
  隐式打开游标
  自动从活动集获取行
  在处理完所有行时关闭游标
优点
  简化代码的编写

游标变量的类型:强游标,弱游标。

游标管理 限制
  不能在程序包中声明游标变量
  远程子程序不能接受游标变量的值
  不能使用比较操作符对游标变量进行相等或不相等测试
  不能将空值赋予游标变量
  表不能存储游标变量的值


-- 包
create or replace package pkg_Test
is
type type_title_rec is record             -- 可以理解为java里面的对象,可以作为参数来传递。--
(
Title c6.a%type,
Price c6.b%type
);

gc_Name_char constant varchar2(12) := 'AZhu';

gv_Age_num number := 18;

function FunGetTitleByTitleID (p_TitleID in c6.a%type) return type_title_rec;

procedure ProGetTitleByTitleID(p_TitleID in c6.a%type,lvv out type_title_rec);

end pkg_Test;


-- 包主体
create or replace package body pkg_Test
is
  function FunGetTitleByTitleID     -- 函数实现,没有create,如果是过程的话,procedure。
  (p_TitleID in c6.a%type)
  return type_title_rec
  as
  lv_title_rec type_title_rec;
  begin
    select a, b into lv_title_rec
    from c6
    where a = p_TitleID;
    return (lv_title_rec);
  end FunGetTitleByTitleID;
 
  procedure ProGetTitleByTitleID
  (p_TitleID in c6.a%type,
   lvv out type_title_rec 
  )
  as
  begin
    select a, b into lvv
    from c6
    where a = p_TitleID;
  end ProGetTitleByTitleID;

end pkg_Test;


set serveroutput on;   --打开输出,每次重起SQLPlus Worksheet需要重新打开输出。

-- 包函数调用
declare
lv_title_rec pkg_Test.type_title_rec;
begin
  lv_title_rec := pkg_Test.FunGetTitleByTitleID('2');  -- 包.函数名
  dbms_output.put_line(lv_title_rec.title);
  dbms_output.put_line(lv_title_rec.price);
end;

-- 包过程调用
declare
lv_title_rec pkg_Test.type_title_rec;
begin
  pkg_Test.ProGetTitleByTitleID('3',lv_title_rec);     -- 包.过程名
  dbms_output.put_line(lv_title_rec.title);
  dbms_output.put_line(lv_title_rec.price);
end;

-- 包中变量和常量的调用及修改值
begin
  dbms_output.put_line(pkg_Test.gv_Age_num);           -- 包.变量名
  dbms_output.put_line(pkg_Test.gc_Name_char);         -- 包.常量名
  pkg_Test.gv_Age_num := 28;
  dbms_output.put_line(pkg_Test.gv_Age_num);           -- 包.变量名
end;

 

where current of c;  -- 表示操作的是当前游标,可以做修改或删除。

 


create or replace function FunGetTitleByTitleID2     -- 函数实现,没有create,如果是过程的话,procedure。
  (p_TitleID in c6.a%type)
  return type_title_rec
  as

  lv_title_rec type_title_rec;
  begin
    select a, b into lv_title_rec
    from c6
    where a = p_TitleID;
    return (lv_title_rec);
  end;


create type add_type3 as object(
  street varchar2(10),  --街道名
  city varchar2(10),    --城市名
  state char(2),        --州代码
  zip   c6.b%type          --邮编     --c6.b%type这样写会报错。
);

 

create type type_title_rec as object    -- is record会报错。
(
  Title number,
  Price varchar2(10)
);


create or replace function FunGetTitleByTitleID2
  (p_TitleID in c6.a%type)
  return c6.a%type
  --return type_title_rec;          -- 返回类型在前,创建类型在后?会报错?
                                    -- 在包声明中都定义好了,在包体中可以直接使用了。--
  as
  type type_title_rec is record     -- is record会报错。
  (
    Title c6.a%type,
    Price c6.b%type
  );
  lv_title_rec type_title_rec;
  begin
    select a,b into lv_title_rec    -- 查询的值必须一一对应,否则报创建的函数带有编译错误。--
    from c6
    where a = p_TitleID;
    --return (lv_title_rec);
    return p_TitleID;
  end;


create or replace function FunGetTitleByTitleID
(p_TitleID in titles.title_id%type)
return type_title_rec                -- 会报错!! 错误:PLS-00498: 在说明一个类型之前对其进行了非法使用

as
type type_title_rec is record
(
Title titles.title%type,
Price titles.price%type
);
lv_title_rec type_title_rec;
begin
  select title, price into lv_title_rec
  from titles
  where title_id = p_TitleID;
  return (lv_title_rec);
end;

####解决方法####
create or replace function FunGetTitleByTitleID
(p_TitleID in titles.title_id%type)
--return type_title_rec                -- 会报错!! 错误:PLS-00498: 在说明一个类型之前对其进行了非法使用
return titles%rowtype                  -- 使用rowtype解决。
as
type type_title_rec is record
(
Title_id titles.title_id%type,
Title titles.title%type,
Price titles.price%type,
Type titles.type%type
);
lv_title_rec type_title_rec;
begin
  select title_id, title, price,type into lv_title_rec
  from titles
  where title_id = p_TitleID;
  return (lv_title_rec);
end;

####调用方法####
declare
lv_rr titles%rowtype;
begin
lv_rr := FunGetTitleByTitleID(2);
dbms_output.put_line(lv_rr.Title_id);
dbms_output.put_line(lv_rr.Title);
dbms_output.put_line(lv_rr.Price);
dbms_output.put_line(lv_rr.Type);
end;


--创建异常测试表--
create table exp1(
  expid int primary key,
  expname varchar2(12) unique,
  expdate date
);

set serveroutput on;      --打开控制台输出--

declare
lv_errnum_num int;
begin
  insert into exp1 values(1,'Exp1','01-1月-05');
  exception
    when others then
    dbms_output.put_line('错误编号:' ||  sqlcode);
    dbms_output.put_line('错误描述:' ||  sqlerrm);
end;

错误编号:-1
错误描述:ORA-00001: 违反唯一约束条件 (NEWLIFEYHJ.SYS_C002167)

insert into exp1 values(1,'Exp1','01-0月-05');    -- 写成0月
错误编号:-1843
错误描述:ORA-01843: 无效的月份

insert into exp1 values('aaa','exp1','01-2月-05'); --'aaa'
错误编号:-1722
错误描述:ORA-01722: 无效数字

declare
lv_errnum_num int;
begin
insert into exp1 values('aaa','exp1','01-2月-05');
exception
when others then
  dbms_output.put_line('错误编号:' ||  sqlcode);
    dbms_output.put_line('错误描述:' ||  sqlerrm);
--if sqlcode = -1 then
  --dbms_output.put_line('名字不能重复!!');
--end if;
  case sqlcode
  when -1 then
    dbms_output.put_line('名字不能重复!!');
  when -1722 then
    dbms_output.put_line('名字必须是数字!!');
  end case;
end;


declare
lv_errnum_num int;
MyFirstException exception;
pragma exception_init(MyFirstException,-0001);  --绑定异常code
begin
insert into exp1 values(1,'exp1','01-2月-05');
exception
  --when dup_val_on_index then
  when MyFirstException then
    dbms_output.put_line('名字不能重复!!');
end;

declare
DUP_VAL_ON_INDEX2 exception;
pragma exception_init(DUP_VAL_ON_INDEX2,-0001);  --系统自己绑定的不需要自己去绑定了!!
begin
  insert into exp1 values(1,'exp1','01-1月-05');
  exception
  when DUP_VAL_ON_INDEX then                     --这样一样可以捕获的到异常!! 写成DUP_VAL_ON_INDEX2也可以!!
    dbms_output.put_line('DoItYourself!');
end;


-- 自定义异常
declare
lv_TitleCount_num numeric(3) := 0;
lv_NoTitles_exp exception;
lv_MoreTitles_exp exception;
begin
  select count(title_id) into lv_TitleCount_num
  from titles;
  dbms_output.put_line(lv_TitleCount_num);       --测试语句,打印出当前值是多少。--
  if lv_TitleCount_num > 0 then
    Raise lv_MoreTitles_exp;
  elsif lv_TitleCount_num <= 0 then
    Raise lv_NoTitles_exp;
  end if;
exception
  when lv_NoTitles_exp then
    dbms_output.put_line ('No Titles!');
  when lv_MoreTitles_exp then
    dbms_output.put_line ('More Titles!');
end;

##raise_application_error应用##
declare
lv_i_num int;
JDI_M exception;
JDI_L exception;
pragma exception_init( JDI_M, -20001);
pragma exception_init( JDI_L, -20998);
begin
  lv_i_num := 8;
  if lv_i_num > 10 then
    raise_application_error( -20001, 'Too Many!');    --错误编号必须介于-20000和-20999之间
  else
    raise_application_error( -20998, 'Too Little!');  --错误编号必须介于-20000和-20999之间
  end if;
exception
  when JDI_M then
    dbms_output.put_line('TM');
  when JDI_L then
    dbms_output.put_line('TL');
end;


declare
lv_TitleCount_num numeric(3) := 0;
lv_NoTitles_exp exception;
lv_MoreTitles_exp exception;
pragma exception_init(lv_NoTitles_exp,-20001);
pragma exception_init(lv_MoreTitles_exp,-20002);
begin
  select count(title_id) into lv_TitleCount_num
  from titles;
  dbms_output.put_line(lv_TitleCount_num);       --测试语句,打印出当前值是多少。--
  if lv_TitleCount_num > 0 then
    Raise_Application_error(-20002,'书籍太多!');
  elsif lv_TitleCount_num <= 0 then
    Raise_Application_error(-20001,'没有书籍!');
  end if;
--exception                                     --如果没有注释,那么执行打印信息。否则输出Raise_Application_error的定义信息。--
  --when lv_NoTitles_exp then
  --  dbms_output.put_line ('No Titles!');
  --when lv_MoreTitles_exp then
  --  dbms_output.put_line ('More Titles!');
end;

posted @ 2013-05-22 15:49  全新时代-小小程序员大梦想  阅读(356)  评论(0编辑  收藏  举报