oracle命令大全

Oracle 命令集合

制作人: 陈杉

1、  创建表空间:

create  tablespace 表空间名称  datafile  ‘文件地址以及文件名’  [ size ]  [ autoextend  [ on | off ] ];

       注:【 size 】 表示要创建的表空间的大小。单位可以为 K 或者 M。

    【 autoextend 】 表示创建的表空间是否为自动扩展类型。

2、  创建新用户:

create  user  用户名  identified  by  密码  [ default  tablespace  表空间名 ] [ temporary  tablespace  表空间名 ];

注:【default】 语句表示为新创建的用户分配一个默认的表空间;【tempporary】表示为新创建的用户提供一个临时的表空间。另外,如果创建数字账户,如 100、123 之类的登陆账户,那么需要将账户用双引号引起来例如:create  user  "101" indentified by  密码~~~~~~; 否则会出现“ORA-01935: 缺失用户或角色名”这样的异常。

3、  为新用户授予权限:

grant  connect  to  用户名;   表示授予用户连接数据库,创建表以及其他结构。

Grant  resource  to  用户名;  表示授予用户使用数据库空间的权限。

Grant  select | update  on  emp  to  用户名;

注:select 表示授予用户查询emp 表的权限,update 表示授予用户修改emp 表的权限。

4、  修改密码:

alter user  用户名 identified  by  新密码;

5、  删除用户:

drop  user  用户名  cascade ;

注:当用户拥有模式对象时必须使用 cascade;

6、  创建表:

create  table  表名称  (字段1  类型,字段2  类型,……..字段N  类型);

7、  修改表结构:

alter  table  表名称  madofy  (列名  类型,………);

表示修改表中的类型和字段的大小。

alter  table  表名称  add  (字段  类型,……..);

表示向表中添加新列。

Alter  table  表名称  drop  column  列名称;

表示删除表中的现有列。

8、  清除表中所有数据:

truncate  table  表名称;

truncate 命令和 delete  命令相似,都可以用于删除表中所有的记录,不同的是:truncate 命令表示删除表中所有记录并立即释放空间,而delete 则需要提交事务后才能释放空间,当确定数据无用时使用truncate 比使用delete 效率更高。

9、  查看表结构:

desc 表名称;

10、              删除表

drop  table  表名称;

11、              查询无重复列:

select  distinct  列名  from  表名;

12、              根据现有表创建新表:

create  table  新表名  as  select  *  from  旧表名;

注:改语句非常灵活,新表中的字段和数据根据查询语句而定。如: 可以将查询的 * 改为旧表中存在的列,可以在查询语句后添加where 条件以控制记录插入到新表。

13、              插入来自其他表的记录:

insert  into  表名A  select  *  from  表名B [ where  条件];

注:改语句要求表A要于表B具有相同的表结构。

14、              将表的操作权限授予给其他用户:

grant  select | delete | update  on  表名 to  用户名 [ whit  grant  option];

注:【with  grant  option】表示改授权用户可以将此权限授予其他用户。另外,改语句还可以只授予用户对某个表的某些列的修改权限,其语法如下:

grant  update (列名1 ,列名2~~~)  on  表名  to  用户名;

15、              撤销已授权用户的权限:

revoke  select | update | insert  on  表名  from  用户名;

16、              集合操作符:

a)         union 操作符用于返回两个查询选定的所有不重复的行。例如:

select  ID  from  表名1  union  select  ID  from 表名2;

b)        union  all  操作符用于返回两个查询选定的所有行。例如:

select  ID  from  表名1  union  all  select  ID  from 表名2;

c)        intersect  操作符用于只返回两个查询选都有的行。例如:

select  ID  from  表名1  intersect  select  ID  from 表名2;

d)        minus  操作符用于返回第一个表有的行而表二没有的行。例如:

select  ID  from  表名1  minus  select  ID  from 表名2;

17、              函数:

a)         日期函数:

详见书56~59页。

b)        字符函数:

详见书59~60页。

c)        数字函数:

详见书60~62页。

d)        其他函数:

详见书63~71页。

18、              表分区:

一般表的分区是在创建表的时候便已经完成。例如:

范围分区:

create  table  表名称

(

        ID  number(4),

        Name  char(20)

)

partition  by  range (列名)

(

        partition  分区名  values  luess  than  (分区边界值1)  [tablespace  表空间名],

        partition  分区名  values  luess  than  (分区边界值2)  [tablespace  表空间名],

        partition  分区名  values  luess  than  (分区边界值3)  [tablespace  表空间名],

partition  分区名  values  luess  than  (maxvalue)  [tablespace  表空间名]

);

散列分区:

partition  by  hash (列名)

(

        partition  分区名  [tablespace  表空间名],

        partition  分区名  [tablespace  表空间名],

        partition  分区名  [tablespace  表空间名],

partition  分区名  [tablespace  表空间名]

);

列表分区:

partition  by  list (列名)

(

        partition  分区名  values (‘匹配值’)  [tablespace  表空间名],

        partition  分区名  values (‘匹配值’)  [tablespace  表空间名],

        partition  分区名  values (‘匹配值’)  [tablespace  表空间名],

partition  分区名  values (‘匹配值’)  [tablespace  表空间名]

);

19、              分区的维护:(主要用于对已经创建的分区进行操作)

添加分区:

alter  table  表名称  add  partition  分区名称  values  less  than  (数字值);

注: 添加分区可以用于所有类型的表分区,其语法与对应的分区语法类似。

删除分区:

alter  table  表名称  drop  partition  分区名称;

注: 删除表分区的前提是必须创建了该分区,另外,在删除分区时,分区中的数据也会删除,所以在删除之前必须确定该分区中的数据已经没有存在的必要。

截断分区:截断分区的作用是删除分区中的所有记录。

   Alter  table  表名称  truncate  partition  分区名称;

合并分区:

alter  table  表名称  merge  partition  分区名称1,分区名称2  into  partition  新分区名称;

注: 合并分区可以将范围分区或复合分区表的两个相邻分区连接起来。结果分区将集成北合并的两个分区的较高上界。

拆分分区:

alter  table  表名称  split  partition  要分区的分区名称  at  (创建分区时的条件值) into(partition 新分区名称1,partition 新分区名称2);

注:拆分分区只可用于范围分区。另外也还可以重命名新分区。例如:

    alter  table  表名称  rename  partition  旧分区名称  to  新分区名称;

20、              表锁定:

行级锁:

select  *  from  表名称  where  条件  for  update  [ of  字段1,字段2,……];

注:该锁为行级锁,只对满足条件的指定的字段实行锁定。

表级锁:

loca  table  表名称  in  share  mode  [ nowait ];

注:【nowait】表示避免因为延迟的等待。该语句只对表实现共享锁,还有其他锁模式。请看书78页

21、              创建同义词:(所谓同义词就是对象的别名)

私有同义词:

create  [ or  replace ]  synonym  新建同义词名称  for  要创建同义词的对象名称;

注:私有同义词,顾名思义,旧时创建以后只能由该创建用户使用。创建它的前提条件是,用户必须具有对该表或其他结构的访问权限。

公有同义词:

create  [ or  replace ]  public  synonym  新建同义词名称  for  要创建同义词的对象名称;

注: 公有同义词对所有的用户都有效,但是创建它的前提条件是:用户必须是管理员的身份。另外当公有同义词和本地对象名称由重复时,本地对象优先。

22、              删除同义词:

drop  [ public ]  synonym  同义词名称;

注: 当要删除公有同义词时,用户页必须时管理员的身份。

23、              序列:(所谓序列,就是实现数据自动递增的种子)

a)         创建序列:

create  sequence  序列名称 

[ start  with  开始的序列号 ]

[ increment  by  序列号的间隔 ]

[ maxvalue  序列号的最大值 | nomaxvalue ]  -- 表示指定序列的最大值。Nomaxvalue 表示没有最大值。

[ minvalue  序列号的最小值 | nominvalue ]  -- 表示指定序列的最小值,它必须小于或等于start with 的值,并且小于 maxvalue。Nominvalue 表示没有最小值。

[ cycle | nocycle ];   -- 表示当序列到达最大或最小值时 是否从头开始

b)        访问序列:

序列名.nextval 表示获得序列的下一个值;――主要用于向表中插入记录。例如:

insert  into  表名称  values (序列名.nextval,~~~~~~~);

序列名.currval  表示获得序列的当前值;―― 主要用于查看。 例如:

select  aa.currval  from  dual; 

注: aa 为已经创建的序列,dual 是系统表。

c)        更改序列:

alter  sequence  序列名称 

[ increment  by  序列号的间隔 ]

[ maxvalue  序列号的最大值 | nomaxvalue ]  -- 表示指定序列的最大值。Nomaxvalue 表示没有最大值。

[ minvalue  序列号的最小值 | nominvalue ]  -- 表示指定序列的最小值,它必须小于或等于start with 的值,并且小于 maxvalue。Nominvalue 表示没有最小值。

[ cycle | nocycle ];  -- 表示当序列到达最大或最小值时 是否从头开始

注:不可以更改序列的start  with 的值。

d)        删除序列:

drop  sequence  序列名;

24、              视图:

a)         创建视图:

create  or  replace  view  视图名称  as 

select  表A.字段1,表A.字段2,……,表B.字段1,表B.字段2……

from  表A,表B  on  表A. 字段=表B.字段;

b)        删除视图:

drop  view  视图名称;

25、              索引:

a)         创建索引:

create  index  索引名称  on  表名称 (列名称)  [ tablespace  表空间名称];

注:索引还有其他多种类型,请参看书102-103页。

另外,如果指定多列,那么表示创建组合索引;

26、              游标的使用:

a)         动态游标:示例如下:

declare

    存储游标的变量 test_tab%rowtype;

--定义游标

cursor 游标名称 is select * from test_tab where 条件; 

begin

        open 游标名称;--打开游标

           loop – 对游标进行循环操作

              fetch 存储游标的变量  into 游标名称; --将游标的值赋给变量

              exit when 游标名称%notfound;  --结束循环的条件

              dbms_output.put_line (游标名称.字段名); --对赋值的变量操作

            end loop;

            close 游标名称;

    end;

b)        循环游标:(特点:可以直接对有表进行操作,不需要打开、显示赋值、显示判断结束的条件、关闭游标等)  建议使用改类型游标。示例如下:

declare

        cursor 游标名称 is select * from  cs_test where name='chenshan'; 

begin

           for 变量 in 游标名称

            loop

               dbms_output.put_line(变量.字段名称);

           end loop;

end;

c)        ref 游标:(特点:可以在运行时才确定游标要执行的sql 语句,更加灵活)。其示例如下:

declare

       type temp is ref cursor;

       aa temp;

begin

     if 条件 then

        open 游标名称 for select * from cs_test where 条件;

     elsif 条件 then

       open 游标名称 for select * from cs_goods where 条件;

     else

         open 游标名称 for select * from cs_test where 条件;

     end if;

     fetch 游标名称 into 存储游标的变量

     loop

         具体的操作;

     end loop;

     close 游标名称;

end;

27、              过程:

a)         创建过程:

create or replace procedure (参数列表)

as

  --本地变量申明

begin

      --过程的主体操作

exception

         when 条件 then

              --错误处理;
end;

b)        :执行过程:

execute  过程名称 (参数列表);

注:过程

c)        :将执行过程的权限授予其他用户

grant  execute  on  过程名  to  用户名;

注:过程的调用不应该在sql 语句块中;

d)        :删除过程

drop  procedure  过程名;

28、              函数:

a)         :创建函数

create  [ or replace ] function function_name(parameter1,parameter2,......)—参数列表

return 要返回的数据类型

is | as

[ 本地变量声明 ];

begin

            【函数主体】;

exception

             when 条件(others)  then

                【错误处理主体】 ;

end;

b)        :调用函数

可以为查询语句:

select  函数名称  from  dual;

也可以为pl / sql 语句块调用

begin

       。。。。。。。。。。。。

       调用函数;

       。。。。。。。。。。。。

end;

c)        将函数的使用权限授予其他用户:

grant  execute  on  函数名  to  用户名;

d)        删除函数:

drop  function  函数名称;

29、              程序包:

a)         程序包规范的创建:

create or replace package cs_manage_findindent as

       --声明函数

function func_addgoodds (goodstypeid  number , goodstypename varchar2) return  varchar2;

       --声明过程

       procedure 过程名称(参数);

       --声明游标

       cursor 游标名称(参数) return 返回的数据类型;

end;

b)        程序包主体的创建:

create  [ or  replace ]  package  body  程序包名称  is | as

       --下面是函数主体

function  func_addgoodds ( goodstypeid  number , goodstypename varchar2 )

return  varchar2  as

        begin

insert  into  cs_ProduceType  values ( goodstypeid , goodstypename );

           return '操作成功' ;

       exception

               when others then

                   return '操作失败' ;

       end ;

       --下面是过程主体

       procedure 过程名 (参数列表) as

        begin

           过程主体;--(pl/sql 语句块)

        exception

              when others then

                  错误主体;

        end;

       --下面是游标主体

cursor 游标名称 (参数列表) return 应该返回的数据类型(一般为表名称或者为 (表名称 % ROWTYPE) ) is  查询语句;

end;

注:程序包主要是用于包含过程,函数,游标等操作的集合,它的使用能够让pl/sql代码变得更加简洁、易懂,同时管理员管理起来也更加轻松。

程序包分为两个部分:一个为规范声明,另一个为程序包主体。顾名思义,规范声明是声明程序包中具体要实现的各种对象,而程序包主体则是具体实现规范声明中已经声明的各种对象。

程序保就好比是一本书,书的目录就相当于程序保的规范声明,而书中的章节内容就相当于是程序包的主体,它是对目录的一个实现。

30、              触发器:

a)         创建触发器:

create or replace trigger 触发器名称

before | after [ delete | update | insert ]

on 表名称

for each row

begin

    --开始实现触发器的主体

insert into cs_test_temp values(:old.name,:old.age,:new.sex);

    dbms_output.put_line('已经启动了触发器!!!');

exception

        when others then

             dbms_output.put_line('发现未知错误!!!');

end;

注:before | after 表示改触发器是在事件之前还是事件之后被触发。

[ delete | update | insert ]表示选择可以触发该触发器的事件。

for each row 表示对每一行的修改都会触发该触发器,即创建了一个行级触发器。

:old.name  表示事件之前name的值。

:new.sex   表示事件之后name的值。

31、              产生随机数字的语法:

num := dbms_random . random ;

32、              删除重复的记录:

delete from  表名称  where  id  in

       ( select  id  from  表名称  group  by  id  having  count( * ) > 1)

and

          ( select  min( rowid )  from  表名称  group  by  id  having  count( * ) > 1) ;

注:group  by  关键字用于将不重复的字段全部列出,以及将重复的字段列出一个。 而having 则表示在group  by  语句后的条件关键字,因为在group  by  后面不能使用where条件关键字来使用条件语句。

33. 主键操作

–添加主键

alter table  tableName

add constraint  primaryKeyName  primary key(主键列名)

--删除主键

alter table  tableName

drop constraint  primaryKeyName 



查询锁定数据库的用户信息以及解除锁定

在Oracle中很多时候会出现用户被锁定的情况,该情况产生的原因很多,在此不做解释!主要讲一下查询被锁定的用户,以及解锁!首先,如出现锁定不能登陆的情况,那么首先需要使用拥有DBA权限的用户进行登陆(一般情况下能够登陆成功)接下来就是使用sql语句查询被锁定的用户!语句如下:

Select   username,account_status from dba_users;    

此时将会列出所有oracle用户名称以及该账户所处的状态,如果状态为:locked,那么表示该用户被锁定,是不能用此账户进行登陆的!解决的办法是解除锁定,如果为 chenshan 这个用户被锁定。示例语句如下:

alter user chenshan  account unlock;

解锁成功以后再次执行上面的查询语句,如果状态为 open,那么恭喜你,解锁成功!



Oracle导入/导出数据库的语法

oracle中除了在Oracle编辑器中用图形化的方式导入文理文件的数据方式外,还可以采用命令行的方式导入数据库,其语法实示例如下:                                                                                                                                                                               imp [username[/password[@service]]]  

步骤:1、首先在进入 dos, 然后切换到 oracle 数据库物理文件所在的目录即(dmp文件所在的目录)。接下来输入下述语句!

    imp username/password@service  file=psmis.dmp fromuser=psmis touser=psmis log=psmis.log 下面就语句的语法做一下解释:

imp :是导入数据库的语法前缀;

username/password@service :意思是登陆指定的service;

file :指的是已经分离的oracle数据库物理文件;

fromuser:指的是来源用户;

touser:指的是目标用户;

log:指的是当前目录下的日志文件;

-------------------以下是转载----------------

在 dos 中查看oracle中的imp,exp命令:
    imp help=y
    exp help=y
1.    导出表数据:
    文件名以backup_yyMMddHHmm.dmp 表示
    dateString=`date +%y%m%d%H%M`
    #echo $dateString
    su - oracle -c "exp userid/password tables=table1,table2 file= path/backup_$dateString.dmp BUFFER=8192 grants=y compress=N"
   compress:N表明导出来的文件不需要压缩放在一个数据块中,当数据库中的表数据特别大的时候,若放在不同的数据库,在恢复的时候会有问题。  
   导出的数据包括表创建语句,序列,触发器等。
2.    导入表数据
   表导入的过程:创建表,导入数据,创建序列
    echo backup file:$1
    fileName=$1
    echo $fileName
    #if [ "$fileName" = ""]
    #then
    #   echo "请指定备份恢复的文件名,请指定绝对文件路径"
    #   exit 0;
    #fi
    #echo fileName=$fileName
    su - oracle -c "imp userid/password file=$fileName show=n buffer=2048000 ignore=Y commit=y grants=y full=y"

    ignore:Y表明忽略表创建的过程,只是将表中的数据导入表中。



第二部分:

--如何在oracle中导入dmp数据库文件?
2006/2/16 zhanghua first create                            

     Oracle数据导入导出imp/exp就相当于oracle数据还原与备份。exp命令可以把数据从远程数据库服务器导出到本地的dmp文件,imp命令可以把dmp文件从本地导入到远处的数据库服务器中。 利用这个功能可以构建两个相同的数据库,一个用来测试,一个用来正式使用。

执行环境:可以在SQLPLUS.EXE或者DOS(命令行)中执行,
DOS中可以执行时由于 在oracle 8i 中  安装目录\ora81\BIN被设置为全局路径,
该目录下有EXP.EXE与IMP.EXE文件被用来执行导入导出。
oracle用java编写,SQLPLUS.EXE、EXP.EXE、IMP.EXE这两个文件有可能是被包装后的类文件。
SQLPLUS.EXE调用EXP.EXE、IMP.EXE所包裹的类,完成导入导出功能。

下面介绍的是导入导出的实例。
数据导出:
1 将数据库TEST完全导出,用户名system 密码manager 导出到D:\daochu.dmp中
   exp system/manager@TEST file=d:\daochu.dmp full=y
2 将数据库中system用户与sys用户的表导出
   exp system/manager@TEST file=d:\daochu.dmp owner=(system,sys)
3 将数据库中的表inner_notify、notify_staff_relat导出
    exp aichannel/aichannel@TESTDB2 file= d:\data\newsmgnt.dmp tables=(inner_notify,notify_staff_relat)

4 将数据库中的表table1中的字段filed1以"00"打头的数据导出
   exp system/manager@TEST file=d:\daochu.dmp tables=(table1) query=\" where filed1 like '00%'\"
 
  上面是常用的导出,对于压缩,既用winzip把dmp文件可以很好的压缩。
  也可以在上面命令后面 加上 compress=y 来实现。

数据的导入
1 将D:\daochu.dmp 中的数据导入 TEST数据库中。
   imp system/manager@TEST  file=d:\daochu.dmp
   imp aichannel/aichannel@HUST full=y  file=file= d:\data\newsmgnt.dmp ignore=y
   上面可能有点问题,因为有的表已经存在,然后它就报错,对该表就不进行导入。
   在后面加上 ignore=y 就可以了。
2 将d:\daochu.dmp中的表table1 导入
imp system/manager@TEST  file=d:\daochu.dmp  tables=(table1)

基本上上面的导入导出够用了。不少情况要先是将表彻底删除,然后导入。

注意:
操作者要有足够的权限,权限不够它会提示。
数据库时可以连上的。可以用tnsping TEST 来获得数据库TEST能否连上。

附录一:
给用户增加导入数据权限的操作
第一,启动sql*puls
第二,以system/manager登陆
第三,create user 用户名 IDENTIFIED BY 密码 (如果已经创建过用户,这步可以省略)
第四,GRANT CREATE USER,DROP USER,ALTER USER ,CREATE ANY VIEW ,
   DROP ANY VIEW,EXP_FULL_DATABASE,IMP_FULL_DATABASE,
      DBA,CONNECT,RESOURCE,CREATE SESSION  TO 用户名字
第五, 运行-cmd-进入dmp文件所在的目录,
      imp userid=system/manager full=y file=*.dmp
      或者 imp userid=system/manager full=y file=filename.dmp

执行示例:
F:\Work\Oracle_Data\backup>imp userid=test/test full=y file=inner_notify.dmp

屏幕显示
Import: Release 8.1.7.0.0 - Production on 星期四 2月 16 16:50:05 2006
(c) Copyright 2000 Oracle Corporation.  All rights reserved.

连接到: Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production
With the Partitioning option
JServer Release 8.1.7.0.0 - Production

经由常规路径导出由EXPORT:V08.01.07创建的文件
已经完成ZHS16GBK字符集和ZHS16GBK NCHAR 字符集中的导入
导出服务器使用UTF8 NCHAR 字符集 (可能的ncharset转换)
. 正在将AICHANNEL的对象导入到 AICHANNEL
. . 正在导入表                  "INNER_NOTIFY"          4行被导入
准备启用约束条件...
成功终止导入,但出现警告。


附录二:
Oracle 不允许直接改变表的拥有者, 利用Export/Import可以达到这一目的.
  先建立import9.par,
  然后,使用时命令如下:imp parfile=/filepath/import9.par
  例 import9.par 内容如下:
        FROMUSER=TGPMS       
        TOUSER=TGPMS2     (注:把表的拥有者由FROMUSER改为TOUSER,FROMUSER和TOUSER的用户可以不同)          
        ROWS=Y
        INDEXES=Y
        GRANTS=Y
        CONSTRAINTS=Y
        BUFFER=409600
        file==/backup/ctgpc_20030623.dmp
        log==/backup/import_20030623.log



34. 游标大全

1.Oracle游标大全
SELECT语句用于从数据库中查询数据,当在PL/SQL中使用SELECT语句时,要与INTO子句一起使用,查询的返回值被赋予INTO子句中的变量,变量的声明是在DELCARE中。SELECT INTO语法如下:
SELECT [DISTICT|ALL]{*|column[,column,...]}
INTO (variable[,variable,...] |record)
FROM {table|(sub-query)}[alias]
WHERE............
PL/SQL中SELECT语句只返回一行数据。如果超过一行数据,那么就要使用显式游标(对游标的讨论我们将在后面进行),INTO子句中要有与SELECT子句中相同列数量的变量。INTO子句中也可以是记录变量。

%TYPE属性
在PL/SQL中可以将变量和常量声明为内建或用户定义的数据类型,以引用一个列名,同时继承他的数据类型和大小。这种动态赋值方法是非常有用的,比如变量引用的列的数据类型和大小改变了,如果使用了%TYPE,那么用户就不必修改代码,否则就必须修改代码。

例:
v_empno SCOTT.EMP.EMPNO%TYPE;
v_salary EMP.SALARY%TYPE;
 不但列名可以使用%TYPE,而且变量、游标、记录,或声明的常量都可以使用%TYPE。这对于定义相同数据类型的变量非常有用。
DELCARE
V_A NUMBER(5):=10;
V_B V_A%TYPE:=15;
V_C V_A%TYPE;
BEGIN
DBMS_OUTPUT.PUT_LINE
('V_A='||V_A||'V_B='||V_B||'V_C='||V_C);
END

SQL>/
V_A=10 V_B=15 V_C=
PL/SQL procedure successfully completed.
SQL>

其他DML语句
其它操作数据的DML语句是:INSERT、UPDATE、DELETE和LOCK TABLE,这些语句在PL/SQL中的语法与在SQL中的语法相同。我们在前面已经讨论过DML语句的使用这里就不再重复了。在DML语句中可以使用任何在DECLARE部分声明的变量,如果是嵌套块,那么要注意变量的作用范围。

例:
CREATE OR REPLACE PROCEDURE FIRE_EMPLOYEE (pempno in number)
 AS
v_ename EMP.ENAME%TYPE;
BEGIN
 SELECT ename INTO v_ename
FROM emp
WHERE empno=p_empno;
INSERT INTO FORMER_EMP(EMPNO,ENAME)
VALUES (p_empno,v_ename);
DELETE FROM emp
WHERE empno=p_empno;
UPDATE former_emp
SET date_deleted=SYSDATE
WHERE empno=p_empno;

EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Employee Number Not Found!');
END

DML语句的结果
当执行一条DML语句后,DML语句的结果保存在四个游标属性中,这些属性用于控制程序流程或者了解程序的状态。当运行DML语句时,PL/SQL打开一个内建游标并处理结果,游标是维护查询结果的内存中的一个区域,游标在运行DML语句时打开,完成后关闭。隐式游标只使用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 ELETE和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语句执行时打开,结束时就立即关闭。

事务控制语句
事务是一个工作的逻辑单元可以包括一个或多个DML语句,事物控制帮助用户保证数据的一致性。如果事务控制逻辑单元中的任何一个DML语句失败,那么整个事务都将回滚,在PL/SQL中用户可以明确地使用COMMIT、ROLLBACK、SAVEPOINT以及SET TRANSACTION语句。
COMMIT语句终止事务,永久保存数据库的变化,同时释放所有LOCK,ROLLBACK终止现行事务释放所有LOCK,但不保存数据库的任何变化,SAVEPOINT用于设置中间点,当事务调用过多的数据库操作时,中间点是非常有用的,SET TRANSACTION用于设置事务属性,比如read-write和隔离级等。

显式游标
当查询返回结果超过一行时,就需要一个显式游标,此时用户不能使用select into语句。PL/SQL管理隐式游标,当查询开始时隐式游标打开,查询结束时隐式游标自动关闭。显式游标在PL/SQL块的声明部分声明,在执行部分或异常处理部分打开,取数据,关闭。

使用游标
这里要做一个声明,我们所说的游标通常是指显式游标,因此从现在起没有特别指明的情况,我们所说的游标都是指显式游标。要在程序中使用游标,必须首先声明游标。

声明游标
语法:
CURSOR cursor_name IS select_statement;

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

例:
DELCARE
CURSOR C_EMP IS SELECT empno,ename,salary
FROM emp
WHERE salary>2000
ORDER BY ename;
........
BEGIN
在游标定义中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

记录变量
定义一个记录变量使用TYPE命令和%ROWTYPE,关于%ROWsTYPE的更多信息请参阅相关资料。
记录变量用于从游标中提取数据行,当游标选择很多列的时候,那么使用记录比为每列声明一个变量要方便得多。
当在表上使用%ROWTYPE并将从游标中取出的值放入记录中时,如果要选择表中所有列,那么在SELECT子句中使用*比将所有列名列出来要安全得多。

例:
SET SERVERIUTPUT ON
DECLARE
R_emp EMP%ROWTYPE;
CURSOR c_emp IS SELECT * FROM emp;
BEGIN
OPEN c_emp;
LOOP
FETCH c_emp INTO r_emp;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUT.PUT.PUT_LINE('Salary of Employee'||r_emp.ename||'is'|| r_emp.salary);
END LOOP;
CLOSE c_emp;
END;

%ROWTYPE也可以用游标名来定义,这样的话就必须要首先声明游标:

SET SERVERIUTPUT ON
DECLARE
CURSOR c_emp IS SELECT ename,salary FROM emp;
R_emp c_emp%ROWTYPE;
BEGIN
OPEN c_emp;
LOOP
FETCH c_emp INTO r_emp;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUT.PUT.PUT_LINE('Salary of Employee'||r_emp.ename||'is'|| r_emp.salary);
END LOOP;
CLOSE c_emp;
END;

带参数的游标
与存储过程和函数相似,可以将参数传递给游标并在查询中使用。这对于处理在某种条件下打开游标的情况非常有用。它的语法如下:

CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;

定义参数的语法如下:
Parameter_name [IN] data_type[{:=|DEFAULT} value]

  与存储过程不同的是,游标只能接受传递的值,而不能返回值。参数只定义数据类型,没有大小。
另外可以给参数设定一个缺省值,当没有参数值传递给游标时,就使用缺省值。游标中定义的参数只是一个占位符,在别处引用该参数不一定可靠。

在打开游标时给参数赋值,语法如下:

OPEN cursor_name[value[,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;

游标FOR循环
在大多数时候我们在设计程序的时候都遵循下面的步骤:
1、打开游标
2、开始循环
3、从游标中取值
4、检查那一行被返回
5、处理
6、关闭循环
7、关闭游标
可以简单的把这一类代码称为游标用于循环。但还有一种循环与这种类型不相同,这就是FOR循环,用于FOR循环的游标按照正常的声明方式声明,它的优点在于不需要显式的打开、关闭、取数据,测试数据的存在、定义存放数据的变量等等。游标FOR循环的语法如下:

FOR record_name IN
(corsor_name[(parameter[,parameter]...)]
| (query_difinition)
LOOP
statements
END LOOP;

下面我们用for循环重写上面的例子:
DECALRE
CURSOR c_dept IS SELECT deptno,dname FROM dept ORDER BY deptno;
CURSOR c_emp (p_dept VARACHAR2) IS
SELECT ename,salary
FROM emp
WHERE deptno=p_dept
ORDER BY ename
v_tot_salary EMP.SALARY%TYPE;
BEGIN
FOR r_dept IN c_dept LOOP
DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
v_tot_salary:=0;
FOR r_emp IN c_emp(r_dept.deptno) 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;

在游标FOR循环中使用查询
在游标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;

游标中的子查询
语法如下:

CURSOR C1 IS SELECT * FROM emp
WHERE deptno NOT IN (SELECT deptno
FROM dept
WHERE dname!='ACCOUNTING');
可以看出与SQL中的子查询没有什么区别。

游标中的更新和删除
在PL/SQL中依然可以使用UPDATE和DELETE语句更新或删除数据行。显式游标只有在需要获得多行数据的情况下使用。PL/SQL提供了仅仅使用游标就可以执行删除或更新记录的方法。
UPDATE或DELETE语句中的WHERE CURRENT OF子串专门处理要执行UPDATE或DELETE操作的表中取出的最近的数据。要使用这个方法,在声明游标时必须使用FOR UPDATE子串,当对话使用FOR UPDATE子串打开一个游标时,所有返回集中的数据行都将处于行级(ROW-LEVEL)独占式锁定,其他对象只能查询这些数据行,不能进行UPDATE、DELETE或SELECT...FOR UPDATE操作。

语法:
FOR UPDATE [OF [schema.]table.column[,[schema.]table.column]..
[nowait]

在多表查询中,使用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 OF comm;
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 c1l;
END LOOP;
END

猜你喜欢

转载自xinyoulinglei.iteye.com/blog/1768008