oracle语句及语法大全分析

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第一章Oracle命令
a)系统管理员连接 conn */* as sysdba
b)查询当前用户 show user
c)创建新用户 create user 用户名 identified by 密码(密码不能以数字开头)。

例如create user abc identified by
cba
d)用户登录 conn 用户名/密码。

例如conn abc/cba
e)用户授权 grant 权限 to 用户。

例如grant connect,resource to abc;grant select on scott.emp to abc
f)收回权限 revoke 权限 from 用户。

例如revoke resource from abc;revoke select on scott.emp from abc
g)修改密码 alter user用户名 identified by 新密码。

例如alter user abc identified by cba12
h)锁定用户 alter user用户名 account lock。

例如alter user scott account lock
i)解锁用户 alter user用户名 account unlock。

例如alter user scott account unlock
j)创建表空间 create tablespace 表空间名 datafile 表空间文件路径 size 初始大小 autoextend on(/off)。

例如create tablespace svse ‘c:\1.dbf’ size 10m autoextend on
k)为某个用户指定表空间 alter user 用户名 default tablespace 表空间名
l)修改表空间的文件大小:alter database datafile 路径(路径要加’) resize 新大小。

例如alter database datafile ‘c:\1.dbf’ resize 20m
m)向表空间添加文件:alter tablespace 表空间名 add datafile 路径 size 初始大小。

例如alter tablespace svse add datafile ‘c:\2.dbf’ size 5m
n)让表空间文件自动扩展:alter database datafile 路径 autoextend on next 每次扩展量 maxsize 文件的最大值。

例如alter database datafile ‘c:\2.dbf’ autoextend on next 5m maxsize 50m
o)修改表空间的名字:alter tablespace 表空间原名 rename to 新名。

注意这个命令是10G新增加的,在9I中不能运行。

p)使表空间临时脱机。

使表空间脱机就相当于sqlserver2005中的分离数据库,就是让服务器不再管理这个表空间了:alter tablespace 表空间名 offline temporary
q)使表空间联机。

相当于sqlserver2005中的附加数据库,就是让服务器重新管理这个表空间:alter tablespace 表空间名 online
r)删除表空间。

如果表空间里面有对象用:drop tablespace 表空间名 including contents。

如果表空间里什么也没有用drop tablespace 表空间名
s)更改环境变量设置每行显示 set linesize 大小设置每页显示 set pagesize 大小。

例如set pagesize 500,set lines 300
t)设置sqlplus代码保存路径:spool on 路径,注意在9i下路径不能加’,在10G下可以加。

保存代码spool off。

例如spool on ‘c:\1.sql’;
u)查看表的结构:desc 表名。

例如:desc scott.emp
v)代码错误后修改:edit/ed。

注意在弹出的文本文件中不能在结尾加分号
w)执行外部文件用下面3个命令中的任何一个都可以:start / @ 文件路径。

例如:@ ‘c:\1.sql’
x)清屏命令:clear screen
第二章Oracle命令
修改会话的日期格式信息:alter session set nls_date_format=’yyyy-mm-dd’
显示当前日期:select sysdate from dual。

注意oracle规定如果一个函数没有参数则不能加(),sysdate就没有参数所以没加()
to_date函数是把一个字符串按指定的格式转换成日期。

例如to_date(‘1-20-2000’,’mm-dd-yyyy’)返回的就是2002年1月20日这个日期
to_char函数把一个日期按指定格式转换为字符。

例如to_char(sysdate, ‘yyyy-mm-dd’)
to_number(‘123’)函数把一个字符串转换为数字
伪列rowid存储的是这条记录在硬盘上的绝对位置
伪列rownum可以在select语句中使用,它返回这条记录是表的第几行记录,如果放在条件语句中,rownum只能和<或者<=连用,例如where rownum<=5是正确的,但rownum>2缺查不出任何结果。

伪列level显示这条记录在表中的层次
oracle中连接2个字符用||而不是+。

例如’ab’||’cd’结果是’abcd’
根据一个旧表创建一个新表create table 新表名 as select 某些列 from 旧表。

例如create table newabc as select * from abc
把一个表中的部分数据插入另一个表,原表不变。

insert into 表名 select 某些列 from 原表名 where …。

可以加条件也可以不加。

例如insert into abc select 一些列 from scott.emp
集合运算
为了演示方便,首先创建2个表
Create table table_a ( a varchar2(10), b varchar2(10) )
Create table table_b ( a varchar2(10), b varchar2(10) )
向table_a插入4行数据:
insert into table_a values(‘1’ , ‘a’ )
Insert into table_a values(‘2’ , ‘a’ )
Insert into table_a values(‘3’ , ‘b’ )
向table_b插入3行数据:
Insert into table_b values(‘2’ , ‘a’ )
Insert into table_b values(‘3’ , ‘a’ )
Insert into table_b values(‘4’ , ‘b’ )
UNION并集运算就是将2个查询的结果合成一个结果,合并时重复的记录只取一次。

例如
select * from table_a union select * from table_b的结果是:
A B
---------- ----------
1 a
2 a
3 b
3 a
4 b
UNION ALL并集运算就是将2个查询的结果合成一个结果,合并时不排除重复的记录。

例如
select * from table_a union all select * from table_b的结果是:
A B
---------- ----------
1 a
2 a
3 b
2 a
3 a
4 b
INTERSECT交集运算就是只返回2个查询中共同的记录。

例如:
select * from table_a intersect select * from table_b 的结果是:
A B
---------- ----------
2 a
MINUS剪集运算就是从第一个查询结果中删除2个查询都有的记录。

例如
select * from table_a minus select * from table_b的结果是:
A B
---------- ----------
1 a
3 b
连接查询
内连接:左表inner join右表 on 条件——满足条件的记录才显示出来。

select table_a.a as aa, table_a.b as ab,
table_b.a as ba, table_b.b as bb
from table_a inner join table_b on table_a.a=table_b.a的结果是:
AA AB BA BB
---------- ---------- ---------- ----------
2 a 2 a
3 b 3 a
外连接:左表full join右表 on 条件——2个表的记录都显示出来,满足条件的就显示为同一行,不满足条件的用null显示。

例如:
select table_a.a as aa, table_a.b as ab,
table_b.a as ba, table_b.b as bb
from table_a full join table_b on table_a.a=table_b.a的结果是:
AA AB BA BB
---------- ---------- ---------- ----------
2 a 2 a
3 b 3 a
1 a
4 b
左连接:左表left join右表 on条件——把左表的记录全部显示出来,右表中满足条件的显示为同一行,不满足的用null 表示。

例如:
select table_a.a as aa, table_a.b as ab,
table_b.a as ba, table_b.b as bb
from table_a left join table_b on table_a.a=table_b.a的结果是:
AA AB BA BB
---------- ---------- ---------- ----------
2 a 2 a
3 b 3 a
1 a
右连接:左表right join右表 on 条件——把右表的记录全部显示出来,左表中满足条件的显示为同一行,不满足的用null 表示。

例如:
select table_a.a as aa, table_a.b as ab,
table_b.a as ba, table_b.b as bb
from table_a right join table_b on table_a.a=table_b.a的结果是:
AA AB BA BB
---------- ---------- ---------- ----------
2 a 2 a
3 b 3 a
4 b
分组函数
avg求平均值
count求记录总数
max求最大值
min求最小值
sum对数字型列求和
分析函数(就是sqlserver2005中的排序函数,语法都完全一样)
row_number() over()对某列排序后再对排序后的结果按顺序编号:
select row_number() over(order by b) as 编号,table_a.* from table_a就是按b列排序,然后编号。

运行结果是:编号 A B
---------- ---------- ----------
1 1 a
2 2 a
3 3 b
4 4 b
注意:row_number()函数和rownum伪列的区别:row_number()是先排序后编号,而rownum是按照记录在表中的位置编号。

rank() over()如果排序列的值相同则编相同的号,但跳空。

select rank() over(order by b) as 编号,table_a.* from table_a运行结果是:
编号 A B
---------- ---------- ----------
1 1 a
1 2 a
3 3 b
3 4 b
dense_rank() over()如果排序列的值相同则编相同的号,但不跳空。

select dense_rank() over(order by b) as 编号, table_a.* from table_a运行结果是:
编号 A B
---------- ---------- ----------
1 1 a
1 2 a
2 3 b
2 4 b
注意:over()函数还可以先分组再排序,请看67页上面2行。

字符函数和日期函数请从61页的下面一行开始看。

Oracle 触发器
触发器是当特定事件出现时自动执行的代码块,是一个特殊的过程.
触发器和过程的区别在于:
过程是由用户或应用程序显式调用的,而触发器是不能被直接调用,ORACLE会在事件请求触发器时,执行适当的触发器触发器能够执行的功能有:
自动生成数据
强制复杂的完整性约束条件
自定义复杂的安全权限
提供审计和日志记录
启用复杂的业务逻辑
创建触发器的语法:
BEFORE和AFTER:指在事件之前或之后激发触发器
instead of:如果使用此子句,表示可以执行触发器代
码来代替导致触发器调用的事件
insert,delete和update:指定构成触发器事件的数据操纵类型,update还可以指定列的列表
referencing 指定新行
触发器的组成:
触发器语句
触发器限制
触发器操作
触发器类型:
行级触发器
语句触发器
instead of触发器只适合于视图
模式触发器
数据库级触发器
启用和禁用触发器:
alert trigger name{ enable | disable}
删除触发器
drop trigger name
内置程序包:
dbmes_output 程序包允许用户从程序包,触发器和存储过程中输出信息
dbms_lob 程序包操作Blob,clob,bfile等到数据类型。

dbms_xmlquery
dbms_random
---------课堂体验---
--创建学生表
create table stuInfo
(
stuId number primary key,
stuname varchar2(10) not null,
stuSex varchar2(2) not null
)
--创建序列
create sequence seqDemo
increment by 1
start with 1
nomaxvalue
nocycle
nocache
--记录stuInfo历史操作
--模拟stuInfo 日志文件
create table logInfo (
idDemo number primary key,
doDemo varchar2(4) not null,
doTime date not null,
oldDemo varchar2(40),
newDemo varchar2(40)
)
------after before触发器---------
--注意:
--特性被动执行
--用途跟踪操作记录禁止操作控制安全
--空间行级[each row] 语句级
--时间before after
--代替instead of
--变异表
create or replace trigger tri_stuInfo
after insert or update or delete
on stuInfo
for each row
begin
--临时表:NEW :OLD
--添加inserting 修改updateing 删除deleteing if inserting then
insert into logInfo
values(seqDemo.Nextval,'添加
',sysdate,'',:NEW.stuID||' '||:NEW.stuName||'
'||:NEW.stuSex);
elsif updating then
insert into logInfo
values(seqDemo.Nextval,'修改
',sysdate,:OLD.stuID||' '||:OLD.stuName|| '
'||:OLD.stuSex,:NEW.stuID||'
'||:NEW.stuName||' '||:NEW.stuSex);
elsif deleting then
insert into logInfo
values(seqDemo.Nextval,'删除
',sysdate,:OLD.stuID||' '||:OLD.stuName||'
'||:OLD.stuSex,'');
end if;
end;
----进行增、删、改来进行触发器的测试
insert into stuInfo
values(1001,'zhang','男')
insert into stuInfo
values(1002,'wang','女')
insert into stuInfo
values(1003,'deng','女')
update stuInfo set stuSex = '男' where stuID = 1002; delete from stuInfo where stuId = 1003;
select * from loginfo
--语句级触发器
create or replace trigger tri_banUser
before insert or update or delete
on logInfo
begin
if user not in ('SCOTT') then
raise_application_error(-20001,'只有SCOTT 才能修改该表!');
end if;
end;
-------替代触发器
-------只能针对视图
--创建成绩表
create table markInfo
(
stuID number references stuInfo(stuID),
score number not null
)
-----加测试数据
insert into markInfo values(1001,80);
insert into markInfo values(1002,70);
-----查看结果
select * from stuInfo;
select * from markInfo;
-----创建视图
create or replace view view_markInfo
as
select stuInfo.stuID,stuName,stuSex,score from stuInfo,markInfo
where stuInfo.stuID = markInfo.stuID;
-----通过视图查看结果
select * from view_markInfo
create or replace trigger tri_delstu instead of delete
on view_markInfo
for each row
begin
delete from markInfo where stuId = :OLD.stuID;
delete from stuInfo where stuId = :OLD.stuID; end;
------对instead of 触发器进行测试
delete from view_markInfo where stuID=1001
select * from loginfo
select * from stuInfo
select * from markInfo
---------------变异表-------------------------
--创建另一个触发器
create or replace trigger tri_demo
before update
on Markinfo -----markInfo就为变异表
for each row
begin
-------当在触发器中对变异表操作时,就会引发异常。

update Markinfo set score=60 where stuID
= :OLD.stuID;
end;
---测试
update markInfo
set score =70
where stuID=1002
----执行时发现有异常抛出,原因是会循环级联触发----------------------程序包------------------------
--1.随机数
select dbms_random.value from dual;
select 40+abs(mod(dbms_random.random,10)) from dual;
--2.Xml
declare
words clob;
xmlStr varchar2(32767);
line varchar2(2000);
line_no number:=1;
begin
words:=dbms_xmlquery.getXML('select * from scott.emp');
xmlStr:=dbms_lob.substr(words,32767);
loop
exit when xmlStr is null;
line:=substr(xmlStr,1,instr(xmlStr,CHR(10))-1);
dbms_output.put_line(line_no||':'||line);
xmlStr:=substr(xmlStr,instr(xmlStr,CHR(10))+1);
line_no:=line_no+1;
end loop;
end;
--3.文件
--定义文件夹命名必须大写
create directory MY_DIR as 'D:\TEMP';
--读文件
declare
inputfile UTL_FILE.file_type; --文件对象
input varchar2(2000);
begin
--指定文件
--3个参数依次为:文件夹文件打开方式[r(读) w(写) a(追加)]
inputfile:=UTL_FILE.fopen('MY_DIR','demo.txt','r');
loop
UTL_FILE.get_line(inputfile,input);
dbms_output.put_line(input);
end loop;
--关闭文件
UTL_FILE.fclose(inputfile);
exception
when no_data_found then dbms_output.put_line('文件末尾!');
end;
--写文件
declare
inputfile UTL_FILE.file_type; --文件对象
input varchar2(2000):='Hello World!';
begin
--指定文件
--3个参数依次为:文件夹文件打开方式[r(读) w(写) a(追加)]
inputfile:=UTL_FILE.fopen('MY_DIR','mydemo.txt','a' );
--写入数据
UTL_FILE.put_line(inputfile,input);
--关闭文件
UTL_FILE.fclose(inputfile);
exception
when no_data_found then dbms_output.put_line('文件末尾!');
end;
Oracle 过程、函数、包、重载、自主事务(2008-05-12 21:21:12)
子程序包的优点有如下:
模块化:通过子程序,可以将程序分解为可管理的,明确的逻辑模块。

可重用性:子程序在创建并执行后,就可以在任意数目的应用程序中使用。

可维持性:子程序可以简化维护操作,因为如果一个程序受到影响,
则只需要修改该子程序的定义。

安全性:用户可以设权限使得访问数据的唯一方式就是通过提供的过程和函数。

过程
创建过程
执行过程
过程参数模式
函数
定义函数的语法的一些限制。

函数只能带有IN参数,而不能带有IN OUT 或OUT参数
参数必须只使用数据库类型,不得使用PL/SQLo类型
函数的返回类型也必须是数据库类型。

创建函数
函数受权
删除函数
从SQL表达式调用函数的限制
从SELECT语句调用的任何函数均不能修改数据库
当远程执行时,函数不得读取或写入程序包中变量的值。

从SELECT,values或SET子句调用的函数可写入变量,其它的则不能写入变量
要执行UPDATE的存储过程,则该函数不能在SQL语句内使用。

自主事务处理
自主事务处理结果的变化不依赖于主事务处理的状态或最终
配置
自主事务处提交或回退时,不影响主事务处理的结果
自主事务处理一旦提交,该自主事务处理结果的变化对于其它事务处理是可见的
自主事务处理可以启动其他自主事务处理。

程序包的优点
模块化
更轻松的应用程序设计
信息隐藏
新增功能
性能更佳
程序包中的游标
使用%rowtype属性根据数据库表定义的记录
根据程序员定义的记录类型的记录
------------------------------课堂体验
---------------------------
select * from emp
--备份
create table Emptest as select * from emp;
select * from Emptest
--pl/sql 块
declare
-- empName Emptest.Ename%type;
-- empSal emptest.sal%type;
type emprowType is record(empName Emptest.Ename%type,empSal emptest.sal%type);
emprow emprowType;
cursor empCursor is select ename,sal from Emptest;
begin
open empCursor ;
loop
fetch empCursor into emprow;
exit when empCursor%notfound;
dbms_output.put_line(emprow.empname || '的工资为:'|| emprow.empsal);
end loop;
close empCursor;
end;
/ *******************
不能重用,不能在外部调用,每次执行它都得重新编译。

这是最大的缺陷。

如果要在外部调用,怎么办?首先有一个名字
解决方案:过程、函数、包、触发器
这里主要讲过程、函数、包
*********************/
-----------------过程---------------
/
**************************************************** ****
过程有些资料书上也叫存储过程,将上面的例子用过程实现如下:
过程着重强调的是业务过程处理
**************************************************** ******/
create or replace procedure proEmp
as
type emprowType is record(empName
Emptest.Ename%type,empSal emptest.sal%type);
emprow emprowType;
cursor empCursor is select ename,sal from Emptest;
begin
open empCursor ;
loop
fetch empCursor into emprow;
exit when empCursor%notfound;
dbms_output.put_line(emprow.empname || '的工资为:'|| emprow.empsal);
end loop;
close empCursor;
end;
--先编译再调用执行
begin
proemp;
end;
/ ********************************************* 注意:在命令窗口,调用如下:
--exec proemp;--注意与在pl/sql中调用的区别
***********************************************/
---输出如下:
/ ******************************
SMITH的工资为:800
ALLEN的工资为:1600
WARD的工资为:1250
JONES的工资为:2975
MARTIN的工资为:1250
BLAKE的工资为:2850
CLARK的工资为:2450
SCOTT的工资为:3000
KING的工资为:5000
TURNER的工资为:1500
ADAMS的工资为:1100
JAMES的工资为:950
FORD的工资为:3000
MILLER的工资为:1300
***************************************/
--假设给每个员工的工资加100元
----带参数的过程--------
--参数有:in out (in out)三种情况
create or replace procedure proEmp(thedept
number,empSal emptest.sal%type,flag in out
varchar2)
as
emprow emptest%rowtype;
cursor empCursor is select * from Emptest
where deptno=thedept for update; begin
open empCursor;
loop
fetch empCursor into emprow;
exit when empCursor%notfound;
dbms_output.put_line(emprow.ename || '的工资为:'|| emprow.sal);
update Emptest set sal = (sal + empsal)
where current of empCursor;
-- dbms_output.put_line(emprow.ename || '
加100元后的工资为:'||
emprow.sal);
--为什么上面输出的结果没有变呢?请思考
end loop;
if empCursor%rowcount = 0 then
flag := '输入的部门号不存在!';
else
flag := '影响的行数为:' || empcursor%rowcount;
end if;
close empCursor;
end;
select * from emptest
----调用执行
declare
flag varchar2(50);
num number;
deptno number;
begin
deptno := '&请输入部门号';
num := '&请输入上调工资的额度';
proemp(deptno,num,flag);
dbms_output.put_line(flag);
end;
/ **************************
注意:
1、in输入参数:关键字可以略,默认就是in,调用过程时,必须传值
2、out输出参数:调用时不用传值,但必须有一个变量参数,以接收输出的结果
必须在PL/SQL中执行
3、in out 输入输出参数: 调用时可以传值,也可以不传值。

是in和out参数的结合产物。

************************************/
----函数
/ ***********************************
函数着重强调的是业务数据处理。

可以有参数列表,只有输入参数。

必须要有返回值
***********************************/
--无参函数
create or replace function funAdd return number
as
numA number;
numb number;
res number;
begin
numA := 10;
numB := 20;
res := numa + numb;
return res;
end;
----调用------------
/ *****************************************
1、与调用ORACLE系统函数一样,如果没参数就不用加圆括号。

2、只能出现在表达式中或select 语句中。

*********************************************/
SELECT funADD FROM DUAL;
--有参函数
create or replace function funAddArgs(numA number,numb number) return number
as
res number;
begin
res := numa + numb;
return res;
end;
-----调用
declare
numa number := 10;
numb number := 20;
res number;
begin
res := funAddArgs(numA ,numb);
dbms_output.put_line('计算结果为:' || res); end;
/ ************************************************ 过程和函数的比较:
**************************************************** /
---------包--------
/ ******************************************** 包是由存储在一起的对象组成的PL/SQL结构,有两部分,独立存在:
包头:包体的声明部分,声明的是全局变量。

包体:包的代码段,只能在包头完成编译后才能进行编译。

********************************************/
-------包头-------
create or replace package packTest
is
procedure proEmp;
function funAddArgs(numA number,numb number) return number;
end packTest ;
------包体-----------
create or replace package body packTest
is
procedure proEmp
as
type emprowType is record(empName Emptest.Ename%type,empSal emptest.sal%type);
emprow emprowType;
cursor empCursor is select ename,sal from Emptest;
begin
open empCursor ;
loop
fetch empCursor into emprow;
exit when empCursor%notfound;
dbms_output.put_line(emprow.empna me || '的工资为:'|| emprow.empsal);
end loop;
close empCursor;
end proEmp;
function funAddArgs(numA number,numb number) return number
as
res number;
begin
res := numa + numb;
return res;
end funAddArgs;
end packTest;
/
**************************************************** 注意:
1、包头和包体中的过程和函数的说明必须一致,其中包括子程序
名和其参数名,以及参数的模式。

2、在包头中也可以定义变量,但定义的变量是全局的,
过程和函数都可以共享
**************************************************** **/
--------调用-----------
begin
packTEST.proEmp;
end;
----------包中子过程的重载---------------
---包头
create or replace package pack
is
function funAdd return number;
function funAdd(numA number,numb number) return number;
end pack;
---包体
create or replace package body pack
is
function funAdd return number
as
numA number;
numb number;
res number;
begin
numA := 10;
numB := 20;
res := numa + numb;
return res;
end funAdd;
function funAdd(numA number,numb number) return number
as
res number;
begin
res := numa + numb;
return res;
end funAdd;
end pack;
-----调用
declare
numa number := 10;
numb number := 20;
res number;
begin
res := pack.funAdd(numA ,numb);
dbms_output.put_line('计算结果为:' || res); end;
--------自主事务处理---
/
**************************************************** **********
自主事务处理(pragma autonomous_transaction包括在过程的声明部分)
不依赖于主事务的处理状态或最终配置
自主事务处理提交或回退时,不影响主事务处理的结果自主事务处理一旦提交,该自主事务处理结果的变化对于其他事务处理时可见的。

自主事务处理可以启动其他自主事务处理。

**************************************************** *************/
create or replace procedure pro
is
pragma autonomous_transaction; ---实现自主事务处理,begin
update emp
set sal=12000 where empno=7369;
rollback;--只会回滚本过程,不会影响主调过程end;
create or replace procedure pro1
is
begin
update emp
set ename ='aaaaa' where empno=7499;
pro;
end;
begin
pro1;
end;
Oracle 游标(2008-05-08 16:33:26)标签:it 教育杂谈技术游标分类:ORACLE
1、游标的引入
查询
SELECT语句用于从数据库中查询数据,当在PL/SQL中使用SELECT语句时,要与INTO子句一起使用,查询的返回值被赋予INTO子句中的变量,变量的声明是在DELCARE中。

SELECT INTO语法如下:
SELECT .... INTO ... FROM 表名... WHERE............
PL/SQL中SELECT语句只返回一行数据。

如果超过一行数据,那么就要使用显式游标(对游标的讨论我们将在后面进行),INTO子句中要有与SELECT子句中相同列数量的变量。

INTO子句中也可以是记录变量。

其他DML语句
其它操作数据的DML语句是:INSERT、UPDATE、DELETE
和LOCK TABLE,这些语句在PL/SQL中的语法与在SQL中的语法相同。

我们在前面已经讨论过DML语句的使用这里就不再重复了。

在DML语句中可以使用任何在DECLARE部分声明的变量,如果是嵌套块,那么要注意变量的作用范围。

DML语句的结果
当执行一条DML语句后,DML语句的结果保存在四个游标属性中,这些属性用于控制程序流程或者了解程序的状态。

当运行DML语句时,PL/SQL打开一个内建游标并处理结果,游标是维护查询结果的内存中的一个区域,游标在运行DML 语句时打开,完成后关闭。

游标分类:
静态游标:分隐式游标和显式游标。

REF游标:分弱类型和强类型,是一种引用类型,类似于指针。

生命周期:
1.打开游标(OPEN)
解析,绑定。

不会从数据库检索数据
2.从游标中获取记录(FETCH INTO)
执行查询,返回结果集。

通常定义局域变量作为从游标获取数据的缓冲区。

3.关闭游标(CLOSE)
完成游标处理,用户不能从游标中获取行。

还可以重新打开。

在PL/SQL中游标名是一个未声明变量,不能给游标名赋值或用于表达式中。

2、隐式游标
只使用SQL%FOUND,SQL%NOTFOUND,SQL%ROWCOUNT三个属性.SQL%FOUND,SQL%NOTFOUND是布尔值,SQL%ROWCOUNT是整数值。

SQL%FOUND和SQL%NOTFOUND
在执行任何DML语句前SQL%FOUND和SQL%NOTFOUND的值都是NULL,在执行DML语句后,SQL%FOUND的属性值将是:. TRUE :INSERT
. TRUE :DELETE和UPDATE,至少有一行被DELETE或UPDATE. . TRUE :SELECT INTO至少返回一行
当SQL%FOUND为TRUE时,SQL%NOTFOUND为FALSE。

SQL%ROWCOUNT
在执行任何DML语句之前,SQL%ROWCOUNT的值都是NULL,对于SELECT INTO语句,如果执行成功,SQL%ROWCOUNT的
值为1,如果没有成功,SQL%ROWCOUNT的值为0,同时产生一个异常NO_DATA_FOUND.
SQL%ISOPEN
SQL%ISOPEN是一个布尔值,如果游标打开,则为TRUE, 如果游标关闭,则为FALSE.对于隐式游标而言SQL%ISOPEN总
是FALSE,这是因为隐式游标在DML语句执行时打开,结束
时就立即关闭。

--//FOUND NOTFOUND ROWCOUNT ISOPEN
SET SERVEROUTPUT ON;
BEGIN
UPDATE stuInfo SET stuName = 'AAA' WHERE stuID =
'001';
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('Update '||SQL%ROWCOUNT||' Lines');
END IF;
IF NOT SQL%ISOPEN THEN
DBMS_OUTPUT.PUT_LINE('游标关闭 ');
END IF;
END;
3、显式游标(分普通和循环游标)
当查询返回结果超过一行时,就需要一个显式游标,此
时用户不能使用select into语句。

PL/SQL管理隐式游标,当查询开始时隐式游标打开,查询结束时隐式游标自动关闭。

显式游标在PL/SQL块的声明部分声明,在执行部分或异常处理部分打开,取数据,关闭。

普通游标的声明
这里要做一个声明,我们所说的游标通常是指显式游标,因此从现在起没有特别指明的情况,我们所说的游标都是指
显式游标。

要在程序中使用游标,必须首先声明游标。

语法: CURSOR cursor_name IS select_statement;
例:
DELCARE
CURSOR C_EMP IS SELECT empno,ename,salary FROM emp WHERE salary>2000 ORDER BY ename;
........
BEGIN
..........
END;
在游标定义中SELECT语句中不一定非要表可以是视图,也可以从多个表或视图中选择的列,甚至可以使用*来选择所有的列。

打开游标
使用游标中的值之前应该首先打开游标,打开游标初始化查询处理。

打开游标的语法是:
OPEN cursor_name
cursor_name是在声明部分定义的游标名。

例:
OPEN C_EMP;
关闭游标
语法:
CLOSE cursor_name
例:
CLOSE C_EMP;
从游标提取数据
从游标得到一行数据使用FETCH命令。

每一次提取数据后,游标都指向结果集的下一行。

语法如下:
FETCH cursor_name INTO variable[,variable,...] 对于SELECT定义的游标的每一列,FETCH变量列表都应该有一个变量与之相对应,变量的类型也要相同。

例:
SET SERVERIUTPUT ON
DECLARE
v_ename EMP.ENAME%TYPE;
v_salary EMP.SALARY%TYPE;
CURSOR c_emp IS SELECT ename,salary FROM emp;
BEGIN
OPEN c_emp;
FETCH c_emp INTO v_ename,v_salary;
DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename||'is'|| v_salary);
FETCH c_emp INTO v_ename,v_salary;
DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename||'is'|| v_salary);
FETCH c_emp INTO v_ename,v_salary;
DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename||'is'|| v_salary);
CLOSE c_emp;
END;
这段代码无疑是非常麻烦的,如果有多行返回结果,可以使用循环并用游标属性为结束循环的条件,以这种方式提取数据,程序的可读性和简洁性都大为提高,下面我们使用循环重新写上面的程序: SET SERVERIUTPUT ON
DECLARE
v_ename EMP.ENAME%TYPE;
v_salary EMP.SALARY%TYPE;
CURSOR c_emp IS SELECT ename,salary FROM emp;
BEGIN
OPEN c_emp;
LOOP
FETCH c_emp INTO v_ename,v_salary;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename||'is'|| v_salary);
END;
带参数的游标
与存储过程和函数相似,可以将参数传递给游标并在查询中使用。

这对于处理在某种条件下打开游标的情况非常有用。

它的语法如下:
CURSOR cursor_name ...... IS select_statement;
定义参数的语法如下:
Parameter_name [IN] data_type[{:=|DEFAULT} value] 与存储过程不同的是,游标只能接受传递的值,而不能返回值。

参数只定义数据类型,没有大小。

另外可以给参数设定一个缺省值,当没有参数值传递给游标时,就使用缺省值。

游标中定义的参数只是一个占位符,在别处引用该参数不一定可靠。

在打开游标时给参数赋值,语法如下:
OPEN cursor_name[value ....];
参数值可以是文字或变量。

例:
DECALRE
CURSOR c_dept IS SELECT * FROM dept ORDER BY deptno;
CURSOR c_emp (p_dept VARACHAR2) IS SELECT ename,salary FROM emp WHERE deptno=p_dept
ORDER BY ename
r_dept DEPT%ROWTYPE;
v_ename EMP.ENAME%TYPE;
v_salary EMP.SALARY%TYPE;
v_tot_salary EMP.SALARY%TYPE;
BEGIN
OPEN c_dept;
LOOP
FETCH c_dept INTO r_dept;
EXIT WHEN c_dept%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Department:'||
r_dept.deptno||'-'||r_dept.dname);
v_tot_salary:=0;
OPEN c_emp(r_dept.deptno);
LOOP
FETCH c_emp INTO v_ename,v_salary;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Name:'|| v_ename||' salary:'||v_salary);
v_tot_salary:=v_tot_salary+v_salary;
END LOOP;
CLOSE c_emp;
DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
END LOOP;
CLOSE c_dept;
END;
在大多数时候我们在设计程序的时候都遵循下面的步骤:
1、打开游标
2、开始循环
3、从游标中取值
4、检查那一行被返回
5、处理
6、关闭循环
7、关闭游标
FOR循环游标
可以简单的把这一类代码称为游标用于循环。

但还有一种循环与这种类型不相同,这就是FOR循环,用于FOR循环的游标按照正常的声明方式声明,它的优点在于不需要显式的打开、关闭、取数据,测试数据的存在、定义存放数据的变量等等。

游标FOR循环的语法如下:
FOR record_name IN
(corsor_name[(parameter[,parameter]...)]
| (query_difinition)
LOOP
statements
END LOOP;
在游标FOR循环中可以定义查询,由于没有显式声明所以游标没有名字,记录名通过游标查询来定义。

DECALRE
v_tot_salary EMP.SALARY%TYPE;
BEGIN
FOR r_dept IN (SELECT deptno,dname FROM dept ORDER BY deptno)
--无为无名游标,不用显示打开和关闭
LOOP
DBMS_OUTPUT.PUT_LINE('Department:'||
r_dept.deptno||'-'||r_dept.dname);
v_tot_salary:=0;
FOR r_emp IN (SELECT ename,salary FROM emp WHERE deptno=p_dept
ORDER BY ename)
LOOP
DBMS_OUTPUT.PUT_LINE('Name:'||
v_ename||' salary:'||v_salary);
v_tot_salary:=v_tot_salary+v_salary;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Toltal Salary for
dept:'|| v_tot_salary);
END LOOP;
END;
游标中的更新和删除
在PL/SQL中依然可以使用UPDATE和DELETE语句更新或
删除数据行。

显式游标只有在需要获得多行数据的情况下使
用。

PL/SQL提供了仅仅使用游标就可以执行删除或更新记录
的方法。

UPDATE或DELETE语句中的WHERE CURRENT OF子串专门处理
要执行UPDATE或DELETE操作的表中取出的最近的数据。


使用这个方法,在声明游标时必须使用FOR UPDATE子串,当
对话使用FOR UPDATE子串打开一个游标时,所有返回集中的
数据行都将处于行级(ROW-LEVEL)独占式锁定,其他对象只
能查询这些数据行,不能进行UPDATE、DELETE或SELECT...FOR UPDATE操作。

语法:
CURSOR 游标名 IS SELECT .... FOR UPDATE [OF ....] 在多表查询中,使用OF子句来锁定特定的表,如果忽略
了OF子句,那么所有表中选择的数据行都将被锁定。

如果这
些数据行已经被其他会话锁定,那么正常情况下ORACLE将等
待,直到数据行解锁。

在UPDATE和DELETE中使用WHERE CURRENT OF子串的语法如
下:
WHERE{CURRENT OF cursor_name|search_condition}
例:
DELCARE
CURSOR c1 IS SELECT empno,salary FROM emp WHERE comm
IS NULL FOR UPDATE;
v_comm NUMBER(10,2);
BEGIN
FOR r1 IN c1
LOOP
IF r1.salary<500 THEN
v_comm:=r1.salary*0.25;
ELSEIF r1.salary<1000 THEN
v_comm:=r1.salary*0.20;
ELSEIF r1.salary<3000 THEN
v_comm:=r1.salary*0.15;
ELSE
v_comm:=r1.salary*0.12;
END IF;
UPDATE emp SET comm=v_comm WHERE CURRENT OF c1; END LOOP;
END
4、REF游标(引用游标)
--------------- 一般最精典的都在后面
------------------------
----游标课堂:
alter user scott account unlock;
--备份操作
create table empTest as select * from emp
select * from empTest
--通过PL/SQL操作一条语句
declare
empName emp.ename%type;
empSal emp.sal%type;
begin
select ename,sal into empname,empsal
from emp where empno = 7369;
dbms_output.put_line(empname || '的工资为:' || empsal);
end;
--注意:在pl/sql中select 语句每次只能返回一条语句并要赋予一个变量,
--如果想取多条会出异常
--问题:经常要取出N条结果集进行处理
--怎么办?游标
--什么是游标:游动的标识,相当于指针。

ORACLE中是一个
仅向前游标
--分类:
--1、静态游标(隐式、显示(普通、循环游标))
--2、引用游标[REF游标](弱类型、强类型)
--游标属性:四个
--%isopen:游标是否打开,布尔值
--%founD: 最近一次操作是否影响数据行数,布尔值
--%notfounD:最近一次操作是否影响数据行数,布尔值 --%rowcount:最近一次操作所影响的总行数,整型值
--如果没有使用DML语句,以上四个属性均不存在,为空--------------1、静态游标---------------
-----隐式--------
--当每执行DML语句时,都会打开隐式游标,将执行的结果保存
--到游标的四个属性中。

--在隐式游标中,我们常用三个属性,
--%founD: 最近一次操作是否影响数据行数,布尔值
--%notfounD:最近一次操作是否影响数据行数,布尔值 --%rowcount:最近一次操作所影响的总行数,整型值
--%isopen:游标打开瞬间你是无法捕获的,值总是false 或者为空.
--隐式游标的名字为:SQL
declare
empName emp.ename%type;
empSal emp.sal%type;
begin
-- dbms_output.put_line(sql%rowcount);
select ename,sal into empname,empsal --DML语句
from emp where empno = 7369;
dbms_output.put_line(empname || '的工资为:' || empsal);
if sql%found then
dbms_output.put_line('true');
else
dbms_output.put_line('false');
end if;
dbms_output.put_line(sql%rowcount);
end;
------显式--------
--当通过DML语句操作时,影响多行就要显示定义游标来处理
--生命周期:
--1、定义游标
--2、打开游标
--3、提取数据
--4、关闭游标
--5、销毁游标
--------普通-------
declare
empName empTest.Ename%type;
empSal empTest.sal%type;
--定义游标
cursor myCursor is select ename,sal from empTest; begin
--打开游标
open myCursor;
--提取数据
loop
fetch myCursor into empName,empSal;
exit when myCursor%notfound ;
dbms_output.put_line(empname || '的工资为:' || empsal);
end loop;
--关闭游标
close myCursor;
end;
---数据的筛选-----
--1、定义游标时筛选
--2、提取数据时通过if语句筛选
--3、带参数游标筛选
----------1、定义游标时筛选----------
declare
empName empTest.Ename%type;
empSal empTest.sal%type;
--定义游标
cursor myCursor is select ename,sal
from empTest where deptno=20;
begin
--打开游标
open myCursor;
--提取数据
loop
fetch myCursor into empName,empSal;
exit when myCursor%notfound ;
dbms_output.put_line(empname || '的工资为:' || empsal);
end loop;
--关闭游标
close myCursor;
end;
-----2、提取数据时通过if语句筛选-------
declare
empName empTest.Ename%type;
empSal empTest.sal%type;
empDeptno empTest.Deptno%type;
--定义游标 cursor myCursor is select ename,sal,deptno
from empTest;
begin
--打开游标
open myCursor;
--提取数据
loop
fetch myCursor into empName,empSal,empdeptno; exit when myCursor%notfound ;
if empdeptno=20 then
dbms_output.put_line(empname || '的工资为:' || empsal);
end if;
end loop;
--关闭游标
close myCursor;
end;
--------3、带参数游标筛选(更灵活)-----------
declare
empName empTest.Ename%type;
empSal empTest.sal%type;
--定义游标
cursor myCursor(empDeptno empTest.Deptno%type) is select ename,sal
from empTest where deptno=empDeptno;
begin
--打开游标(传递参数)
open myCursor(&请输入部门的编号);
--提取数据
loop
fetch myCursor into empName,empSal;
exit when myCursor%notfound ;
dbms_output.put_line(empname || '的工资为:' || empsal);
end loop;
--关闭游标
close myCursor;
end;
-------循环游标(更方便)-------
--相当于C#中的foreach语句
--用来循环遍历
declare
--定义游标
cursor myCursor is select ename,sal from empTest; begin。

相关文档
最新文档