Oracle Class6-1. PL/SQL 简介,数据类型,逻辑比较,控制结构,错误处理

------------------------2013-5-16------------------------

1.sql概念,主要特点,使用sql工具,如何访问及本书实例两个数据表

2.单个表查询

3.多个表查询

4.复杂的嵌套查询

5.查询函数

6.sql录入数据

7.sql删除数据

8.sql更新数据

sql已经被ANSI(美国国家标准化组织)确定为数据库系统的工业标准。

DQL:查询

DDL:建立,删除和修改数据对象

DML:完成数据操作的命令,包括查询。

DCL:控制对数据库的访问,服务器的关闭,启动等。

--\Class1\扩展\Oracle9.0入门_基本SQL.pdf

--\Class6\扩展\Oracle9.0入门_04_SQL.pdf 相同

set serveroutput on 打开输出。

case .. when .. then .. else .. end case条件判断

declare

lv_Age_num number default 99;

lv_Name_char varchar2(8) := 'AZhu';

lc_Sex_char constant char(8) := 'Male';

begin

dbms_output.put_line (lv_Age_num);

dbms_output.put_line ('===========');

lv_Age_num := 15;

lv_Name_char := 'ANiu';

--lc_Sex_char := 'Female';

case lv_Age_num

when 12 then

dbms_output.put_line (lv_Name_char || '大于10!');

when 10 then

dbms_output.put_line (lv_Name_char || '等于10!');

else

dbms_output.put_line (lv_Name_char || '小于10!');

end case;

end;

declare

lv_Age_num number default 99;

lv_Name_char varchar2(8) := 'AZhu';

lc_Sex_char constant char(8) := 'Male';

begin

dbms_output.put_line (lv_Age_num);

dbms_output.put_line ('===========');

lv_Age_num := 9;

lv_Name_char := 'ANiu';

--lc_Sex_char := 'Female';

case

when lv_Age_num > 10 then

dbms_output.put_line (lv_Name_char || '大于10!');

when lv_Age_num = 10 then

dbms_output.put_line (lv_Name_char || '等于10!');

else

dbms_output.put_line (lv_Name_char || '小于10!');

end case;

end;

sql%found判断,返回影响的行数:sql%rowcount

begin

update class6 set cname = 'PP' where cid = 3;

if sql%found then

dbms_output.put_line(sql%rowcount);

else

dbms_output.put_line('OhNo!');

end if;

end;

for循环

for lv_ID_num in 2 .. 4 --退出条件--

loop

end loop;

declare

lv_ID_num2 int := 12;

begin

for lv_ID_num in 8 .. 10 --for变量,--退出条件--

loop

insert into Class6 values (lv_ID_num2, 'ANiu' || to_char(lv_ID_num2));

lv_ID_num2 := lv_ID_num2 + 1; --如果写成lv_ID_num := lv_ID_num + 1; 会报错。

end loop;

commit;

end;

while lv_ID_num < 8 --退出条件--

loop

end loop;

loop

exit when lv_ID_num = 21; --退出条件--

end loop;

declare

lv_Title_char varchar2(80);

lv_Price_num number(19,4);

begin

select cname,cid

into lv_Title_char, lv_Price_num --可以赋予给多个变量--

from class6

where c; --'2'可以写成变量赋值的方式--

dbms_output.put_line (lv_Title_char);

dbms_output.put_line (lv_Price_num);

end;

declare

-- 定义记录(Record)

type type_Title is record --创建类型--

(

lv_Title_char varchar2(80),

lv_Price_num number(19,4)

);

lv_title type_Title;

lv_TitleID_char varchar2(80);

begin

lv_TitleID_char := 3;

select cname,cid

into lv_title --赋予给记录类型变量--

from class6

where cid= lv_TitleID_char;

dbms_output.put_line (lv_title.lv_Title_char);

dbms_output.put_line (lv_title.lv_Price_num);

end;

###

create type add_type as object(

street varchar2(10), --街道名

city varchar2(10), --城市名

state char(2), --州代码

zip number --邮编

);

### -->ORACLE埃里森4.txt

创建视图

create view viewTitles

as

select cid, cname from class6

declare

-- 定义记录(Record)

lv_title viewTitles%rowtype; --视图类型方式--, --表类型: lv_title class6%rowtype;

lv_TitleID_char varchar2(80);

begin

lv_TitleID_char := 3;

select cid, cname

into lv_title --赋予给记录类型变量--

from class6

where cid= lv_TitleID_char;

dbms_output.put_line (lv_title.cid);

dbms_output.put_line (lv_title.cname);

end;

%type理解,只要是类型都可以引用.

lv_Name_char varchar2(8) := 'AZhu';

lv_Sex_char lv_Name_char%type := 'Male'; --引用变量--

---------------------游标完整例子---------------------

declare

-- 声明游标(关联Select语句)

cursor cur_Titles is select cname,cid from class6;

lv_Title_char class6.cname%type;

lv_Price_num class6.cid%type;

begin

-- 打开游标

open cur_Titles;

-- 提取游标

fetch cur_Titles into lv_Title_char, lv_Price_num;

loop

exit when not cur_Titles%Found; --退出循环条件

dbms_output.put_line ('游标demo========');

dbms_output.put_line (lv_Title_char);

dbms_output.put_line (lv_Price_num);

fetch cur_Titles into lv_Title_char, lv_Price_num; --循环读取

end loop;

-- 关闭游标

close cur_Titles;

end;

--游标类型--

declare

-- 声明游标(关联Select语句)

cursor cur_Titles is select cname,cid from class6;

lv_title_rec cur_Titles%rowtype; --引用游标类型--

begin

-- 打开游标

open cur_Titles;

-- 提取游标

fetch cur_Titles into lv_title_rec;

loop

exit when not cur_Titles%Found; --退出循环条件

dbms_output.put_line ('游标demo========');

dbms_output.put_line (lv_title_rec.cid);

dbms_output.put_line (lv_title_rec.cname);

fetch cur_Titles into lv_title_rec; --循环读取

end loop;

-- 关闭游标

close cur_Titles;

end;

select .. for update ..

规则是:FOR UPDATE语句将锁住查询结果中的元组,这些元组将不能被其他事务的UPDATE,DELETE和FOR UPDATE操作,直到本事务提交。

在newlifeyhj帐户下面建立scott.emp表的结构和数据用来测试:

create table class6emp as

select * from scott.emp;

select sal from class6emp where job = 'CLERK';

SAL

----------

800

1100

950

1300

##修改,取当前游标的记录.where current of c##

create or replace procedure proGeMing2

as

cursor c is select empno, job, sal from class6emp for update;

lv_emp_rec c%rowtype; --那么这行不要

begin

open c; --那么这行不要

--for lv_emp_rec in c --另外一种fetch方式--

loop

fetch c into lv_emp_rec; --那么这行不要

exit when not c%found; --那么这行不要

case lv_emp_rec.job

when 'CLERK' then

update class6emp set sal = sal * 2 where current of c; --c是游标

when 'SALESMAN' then

update class6emp set sal = sal / 2 where current of c;

when 'MANAGER' then

update class6emp set sal = 0 where current of c;

else

update class6emp set sal = 250 where current of c;

end case;

end loop;

close c; --那么这行不要

end;

begin

proGeMing2;

end;

select sal from class6emp where job = 'CLERK';

SAL

----------

1600

2200

1900

2600

create or replace procedure proGeMing2

as

cursor c is select empno, job, sal from class6emp for update;

begin

for lv_emp_rec in c --另外一种fetch方式--

loop

case lv_emp_rec.job

when 'CLERK' then

update class6emp set sal = sal * 2 where current of c; --c是游标

when 'SALESMAN' then

update class6emp set sal = sal / 2 where current of c;

when 'MANAGER' then

update class6emp set sal = 0 where current of c;

else

update class6emp set sal = 250 where current of c;

end case;

end loop;

end;

select sal from class6emp where job = 'CLERK';

SAL

----------

3200

4400

3800

5200

不使用游标的方式,直接查询。那么就不可以用where current of c

create or replace procedure proGeMing2

as

begin

for lv_emp_rec in (select empno, job, sal from class6emp for update)

loop

case lv_emp_rec.job

when 'CLERK' then

update class6emp set sal = sal * 2 where empno = lv_emp_rec.empno;

when 'SALESMAN' then

update class6emp set sal = sal / 2 where empno = lv_emp_rec.empno;

when 'MANAGER' then

update class6emp set sal = 0 where empno = lv_emp_rec.empno;

else

update class6emp set sal = 250 where empno = lv_emp_rec.empno;

end case;

end loop;

end;

select sal from class6emp where job = 'CLERK';

SAL

----------

6400

8800

7600

10400

##带参数的游标## 变量方式

declare

-- 声明参数游标

cursor cur_Titles(p_t class6.cid%type)

is

select cname,cid from class6 where cid = p_t;

lv_Title_char class6.cname%type;

lv_Price_num class6.cid%type;

begin

-- 打开游标

open cur_Titles('2'); --参数游标--

loop

-- 提取游标

fetch cur_Titles into lv_Title_char, lv_Price_num;

exit when not cur_Titles%Found;

dbms_output.put_line ('========');

dbms_output.put_line (lv_Title_char);

dbms_output.put_line (lv_Price_num);

end loop;

-- 关闭游标

close cur_Titles;

-- 打开游标

open cur_Titles('3'); --参数游标--

loop

-- 提取游标

fetch cur_Titles into lv_Title_char, lv_Price_num;

exit when cur_Titles%notFound;

dbms_output.put_line ('========');

dbms_output.put_line (lv_Title_char);

dbms_output.put_line (lv_Price_num);

end loop;

-- 关闭游标

close cur_Titles;

end;

--记录方式存储--

declare

type ttt is record(

lv_Title_char class6.cname%type,

lv_Price_num class6.cid%type

);

-- 声明参数游标

cursor cur_Titles(p_t class6.cid%type)

is

select cname,cid from class6 where cid = p_t;

--lv_Title_char class6.cname%type;

--lv_Price_num class6.cid%type;

objttt ttt;

begin

-- 打开游标

open cur_Titles('2'); --参数游标--

loop

-- 提取游标

--fetch cur_Titles into lv_Title_char, lv_Price_num;

fetch cur_Titles into objttt;

exit when not cur_Titles%Found;

dbms_output.put_line ('========');

dbms_output.put_line (objttt.lv_Title_char);

dbms_output.put_line (objttt.lv_Price_num);

--如果游标有多条记录,那么循环取。

end loop;

-- 关闭游标

close cur_Titles;

end;

loop

-- 提取游标

fetch cur_Titles into objttt;

end loop;

-- 提取游标

fetch cur_Titles into objttt;

loop

fetch cur_Titles into objttt; --需要再次提取游标,便于循环。

end loop;

##定义引用游标##

declare

type ttt is record(

lv_Title_char class6.cname%type,

lv_Price_num class6.cid%type

);

-- 定义引用游标

type type_Titles_cur is ref cursor; --这个地方是关键。

-- 声明游标

cur_Titles type_Titles_cur;

objttt ttt;

begin

-- 打开游标

open cur_Titles

for

select cname, cid from class6; --给游标赋予值。

loop

-- 提取游标

fetch cur_Titles into objttt;

exit when not cur_Titles%Found;

dbms_output.put_line ('========');

dbms_output.put_line (objttt.lv_Title_char);

dbms_output.put_line (objttt.lv_Price_num);

end loop;

-- 关闭游标

close cur_Titles;

end;

##循环游标##

-- 循环游标

declare

-- 定义记录(Record)

-- 声明游标

cursor cur_Titles

is

select cid, cname from class6;

begin

-- 自动打开游标

-- 自动提取游标存储到一个自动定义的记录变量

-- 在循环结束部分自动提取下一条记录

-- 当读到游标结尾自动关闭游标

for lv_Title_type in cur_Titles

loop

dbms_output.put_line ('========');

dbms_output.put_line (lv_Title_type.cid);

dbms_output.put_line (lv_Title_type.cname);

end loop;

-- 关闭游标

end;

##隐式游标##

-- 隐式游标

declare

-- 定义记录(Record)

-- 自动声明游标

begin

-- 自动打开游标

-- 自动提取游标存储到一个自动定义的记录变量

-- 在循环结束部分自动提取下一条记录

-- 当读到游标结尾自动关闭游标

for lv_Title_type in (select cid, cname from class6)

loop

dbms_output.put_line ('========');

dbms_output.put_line (lv_Title_type.cid);

dbms_output.put_line (lv_Title_type.cname);

end loop;

-- 关闭游标

end;

PRAGMA EXCEPTION_INIT的用法 --自动触发,而不要手动raise 异常名; --

http://blog.csdn.net/wanggangytsoft/article/details/5408692

ora-01843: 这个错误代表无效的月份一般在日期转化的时候会提示。

ORA-00001: 违反唯一约束条件

ORA-06511 CURSOR_ALREADY_OPEN: 程序尝试打开一个已经打开的游标。一个游标在重新打开之前必须关闭。

ORA-00001 DUP_VAL_ON_INDEX: 唯一索引上有重复值

-- 自定义错误消息

-- Raise_Application_error

raise_application_error(-20001, '没有!');

ORA-01722 invalid number 无效数字

ORA-01476: divisor is equal to zero 这个错误是sql语句中存在除数为0的情况

ora-01422:输出值太多。查询返回的记录行大于1。

NO_DATA_FOUND

##游标异常##

declare

-- 声明游标

cursor cur_Titles

is

select * from class6;

begin

-- 打开游标

open cur_Titles;

open cur_Titles;

-- 关闭游标

close cur_Titles;

exception

when CURSOR_ALREADY_OPEN then --重复打开问题-- CURSOR_ALREADY_OPEN

dbms_output.put_line('Cursor is Opened!');

dbms_output.put_line('Cursor is Opened!');

end;

#存储过程参数 in 是参数的默认模式。# in, out, in out三种类型。

##创建存储过程##

create or replace procedure GetTitle

(

p_titleid in class6.cid%type := '2',

p_title out class6.cid%type,

p_price out class6.cname%type

)

as

begin

select cid, cname into p_title, p_price from class6 where cid = p_titleid;

end;

##调用存储过程##

declare

lv_title_char class6.cid%type;

lv_price_num class6.cname%type;

begin

GetTitle (p_title => lv_title_char, p_price => lv_price_num); --参数名称要和过程定义的相同--,否则参数个数不匹配。

--GetTitle (4,lv_title_char, lv_price_num); --参数接受,个数匹配--这样也可以的!!! --

dbms_output.put_line(lv_title_char);

dbms_output.put_line(lv_price_num);

end;

create or replace procedure GetTitle

(

p_title out class6.cid%type,

p_price out class6.cname%type

)

as

begin

select cid, cname into p_title, p_price from class6 where cid = 2;

end;

declare

lv_title_char class6.cid%type;

lv_price_num class6.cname%type;

begin

GetTitle (lv_title_char, lv_price_num); --参数接受,个数匹配--

dbms_output.put_line(lv_title_char);

dbms_output.put_line(lv_price_num);

end;

create or replace procedure GetTitleByTitleID2

(

p_TitleID in class6.cid%type,

p_Title out class6.cid%type,

p_Price out class6.cname%type --关键点:这个地方没有逗号。--

)

as

begin

select cid, cname into p_Title, p_Price from class6 where cid = p_TitleID;

end;

exec 不要写,否则会报错。

set serveroutput on; 打开,否则无法看到输出信息,pl/sql developer 测试窗口可以运行存储过程。

set serveroutput on;

declare

lv_Title class6.cid%type;

lv_Price class6.cname%type;

begin

GetTitleByTitleID2 ( 2, lv_Title,lv_Price);

dbms_output.put_line('----' || lv_Title);

dbms_output.put_line('====' || lv_Price);

end;

综合存储过程和调用与过程的对比。

declare

lv_Title class6.cid%type;

lv_Price class6.cname%type;

begin

select cid, cname into lv_Title, lv_Price from class6 where cid = 2;

dbms_output.put_line('----' || lv_Title);

dbms_output.put_line('====' || lv_Price);

end;

#类型的引用可以基于表,也可以基于视图。!!!#

##函数## 与存储过程的区别,是函数是有返回值的。

--创建函数

create or replace function funGetTotalQtyByTitleID

(

p_titleid in class6.cid%type

)

return class6.cname%type --返回类型--

as

p_totalqty class6.cname%type;

begin

select cname into p_totalqty from class6 where cid = p_titleid;

return (p_totalqty); --返回值--与返回类型一一匹配

end;

#函数的调用#与系统函数的调用和使用是一样的

select funGetTotalQtyByTitleID('4') from dual;

-- 赋值语句

declare

p_totalqty class6.cname%type;

begin

p_totalQty := funGetTotalQtyByTitleID('5');

dbms_output.put_line(p_totalqty);

end;