甘草轩

Never surrender to complexity
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Oracle & PL/SQL

Posted on 2006-07-27 18:02  甘草轩  阅读(2424)  评论(2编辑  收藏  举报

PL/SQL语言基础

PL/SQLORACLE对标准数据库语言的扩展,ORACLE公司已经将PL/SQL整合到ORACLE 服务器和其他工具中了,近几年中更多的开发人员和DBA开始使用PL/SQL,本文将讲述PL/SQL基础语法,结构和组件、以及如何设计并执行一个PL/SQL程序。

  PL/SQL的优点

  从版本6开始PL/SQL就被可靠的整合到ORACLE中了,一旦掌握PL/SQL的优点以及其独有的数据管理的便利性,那么你很难想象ORACLE缺了PL/SQL的情形。PL/SQL 不是一个独立的产品,他是一个整合到ORACLE服务器和ORACLE工具中的技术,可以把PL/SQL看作ORACLE服务器内的一个引擎,sql语句执行者处理单个的sql语句,PL/SQL引擎处理PL/SQL程序块。当PL/SQL程序块在PL/SQL引擎处理时,ORACLE服务器中的SQL语句执行器处理pl/sql程序块中的SQL语句。

  PL/SQL的优点如下:

  . PL/SQL是一种高性能的基于事务处理的语言,能运行在任何ORACLE环境中,支持所有数据处理命令。通过使用PL/SQL程序单元处理SQL的数据定义和数据控制元素。
  . PL/SQL支持所有SQL数据类型和所有SQL函数,同时支持所有ORACLE对象类型
  . PL/SQL块可以被命名和存储在ORACLE服务器中,同时也能被其他的PL/SQL程序或SQL命令调用,任何客户/服务器工具都能访问PL/SQL程序,具有很好的可重用性。
  . 可以使用ORACLE数据工具管理存储在服务器中的PL/SQL程序的安全性。可以授权或撤销数据库其他用户访问PL/SQL程序的能力。
  . PL/SQL代码可以使用任何ASCII文本编辑器编写,所以对任何ORACLE能够运行的操作系统都是非常便利的
  . 对于SQLORACLE必须在同一时间处理每一条SQL语句,在网络环境下这就意味作每一个独立的调用都必须被oracle服务器处理,这就占用大量的服务器时间,同时导致网络拥挤。而PL/SQL是以整个语句块发给服务器,这就降低了网络拥挤。

  PL/SQL块结构

  PL/SQL是一种块结构的语言,组成PL/SQL程序的单元是逻辑块,一个PL/SQL 程序包含了一个或多个逻辑块,每个块都可以划分为三个部分。与其他语言相同,变量在使用之前必须声明,PL/SQL提供了独立的专门用于处理异常的部分,下面描述了PL/SQL块的不同部分:

  声明部分(Declaration section)

  声明部分包含了变量和常量的数据类型和初始值。这个部分是由关键字DECLARE开始,如果不需要声明变量或常量,那么可以忽略这一部分;需要说明的是游标的声明也在这一部分。

  执行部分(Executable section)

  执行部分是PL/SQL块中的指令部分,由关键字BEGIN开始,所有的可执行语句都放在这一部分,其他的PL/SQL块也可以放在这一部分。

  异常处理部分(Exception section)

  这一部分是可选的,在这一部分中处理异常或错误,对异常处理的详细讨论我们在后面进行。

  PL/SQL块语法

[DECLARE]
---declaration statements
BEGIN
---executable statements
[EXCEPTION]
---exception statements
END


  PL/SQL块中的每一条语句都必须以分号结束,SQL语句可以使多行的,但分号表示该语句的结束。一行中可以有多条SQL语句,他们之间以分号分隔。每一个PL/SQL块由BEGINDECLARE开始,以END结束。注释由--标示。

  PL/SQL块的命名和匿名

  PL/SQL程序块可以是一个命名的程序块也可以是一个匿名程序块。匿名程序块可以用在服务器端也可以用在客户端。

  命名程序块可以出现在其他PL/SQL程序块的声明部分,这方面比较明显的是子程序,子程序可以在执行部分引用,也可以在异常处理部分引用。

  PL/SQL程序块可背独立编译并存储在数据库中,任何与数据库相连接的应用程序都可以访问这些存储的PL/SQL程序块。ORACLE提供了四种类型的可存储的程序:

   . 函数
   . 过程
   .
   . 触发器

  函数

  函数是命名了的、存储在数据库中的PL/SQL程序块。函数接受零个或多个输入参数,有一个返回值,返回值的数据类型在创建函数时定义。定义函数的语法如下:

FUNCTION name [{parameter[,parameter,])] RETURN datatypes IS
[local declarations]
BEGIN
execute statements
[EXCEPTION
exception handlers
]
END [name]


  过程

  存储过程是一个PL/SQL程序块,接受零个或多个参数作为输入(INPUT)或输出(OUTPUT)、或既作输入又作输出(INOUT),与函数不同,存储过程没有返回值,存储过程不能由SQL语句直接使用,只能通过EXECUT命令或PL/SQL程序块内部调用,定义存储过程的语法如下:

PROCEDURE name [(parameter[,parameter,])] IS
[local declarations]
BEGIN
execute statements
[EXCEPTION
exception handlers 
]
END [name]


  (package)

  包其实就是被组合在一起的相关对象的集合,当包中任何函数或存储过程被调用,包就被加载入内存中,包中的任何函数或存储过程的子程序访问速度将大大加快。
包由两个部分组成:规范和包主体(body),规范描述变量、常量、游标、和子程序,包体完全定义子程序和游标。

  触发器(trigger)

  触发器与一个表或数据库事件联系在一起的,当一个触发器事件发生时,定义在表上的触发器被触发。  

变量和常量

  变量存放在内存中以获得值,能被PL/SQL块引用。你可以把变量想象成一个可储藏东西的容器,容器内的东西是可以改变的。

  声明变量

  变量一般都在PL/SQL块的声明部分声明,PL/SQL是一种强壮的类型语言,这就是说在引用变量前必须首先声明,要在执行或异常处理部分使用变量,那么变量必须首先在声明部分进行声明。

  声明变量的语法如下:

Variable_name [CONSTANT] databyte [NOT NULL][:=|DEFAULT expression]


  注意:可以在声明变量的同时给变量强制性的加上NOT NULL约束条件,此时变量在初始化时必须赋值。

  给变量赋值

  给变量赋值有两种方式:

  . 直接给变量赋值
   X:=200;
   Y=Y+(X*20);

  . 通过SQL SELECT INTO FETCH INTO给变量赋值    

SELECT SUM(SALARY),SUM(SALARY*0.1)
      
INTO TOTAL_SALARY,TATAL_COMMISSION
      
FROM EMPLOYEE
      
WHERE DEPT=10;


  常量

  常量与变量相似,但常量的值在程序内部不能改变,常量的值在定义时赋予,,他的声明方式与变量相似,但必须包括关键字CONSTANT。常量和变量都可被定义为SQL和用户定义的数据类型。

ZERO_VALUE CONSTANT NUMBER:=0;


  这个语句定了一个名叫ZERO_VALUE、数据类型是NUMBER、值为0的常量。

  标量(scalar)数据类型

  标量(scalar)数据类型没有内部组件,他们大致可分为以下四类:

   . number
   . character
   . date/time
   . boolean

  表1显示了数字数据类型;表2显示了字符数据类型;表3显示了日期和布尔数据类型。
  表1 Scalar Types:Numeric

Datatype

Range

Subtypes

description

BINARY_INTEGER

-214748-2147483647

NATURAL
NATURAL
NPOSITIVE
POSITIVEN
SIGNTYPE

用于存储单字节整数。
要求存储长度低于NUMBER值。
用于限制范围的子类型(SUBTYPE):
 NATURAL:用于非负数
 POSITIVE:只用于正数
 NATURALN:只用于非负数和非NULL
 POSITIVEN:只用于正数,不能用于NULL
 SIGNTYPE:只有值:-101.

NUMBER

1.0E-130-9.99E125

DEC
DECIMAL
DOUBLE
PRECISION
FLOAT
INTEGERIC
INT
NUMERIC
REAL
SMALLINT

存储数字值,包括整数和浮点数。可以选择精度和刻度方式,语法:
number[
[,]]
缺省的精度是38,scale0.

PLS_INTEGER

-2147483647-2147483647

 

BINARY_INTEGER基本相同,但采用机器运算时,PLS_INTEGER提供更好的性能


  表2 字符数据类型

datatype

rang

subtype

description

CHAR

最大长度32767字节

CHARACTER

存储定长字符串,如果长度没有确定,缺省是1

LONG

最大长度2147483647字节

 

存储可变长度字符串

RAW

最大长度32767字节

 

用于存储二进制数据和字节字符串,当在两个数据库之间进行传递时,RAW数据不在字符集之间进行转换。

LONGRAW

最大长度2147483647

 

LONG数据类型相似,同样他也不能在字符集之间进行转换。

ROWID

18个字节

 

与数据库ROWID伪列类型相同,能够存储一个行标示符,可以将行标示符看作数据库中每一行的唯一键值。

VARCHAR2

最大长度32767字节

STRINGVARCHAR

VARCHAR数据类型相似,存储可变长度的字符串。声明方法与VARCHAR相同


  表3 DATEBOOLEAN

datatype

range

description

BOOLEAN

TRUE/FALSE

存储逻辑值TRUEFALSE,无参数

DATE

01/01/4712 BC

存储固定长的日期和时间值,日期值中包含时间


  LOB数据类型

  LOB(大对象,Large object) 数据类型用于存储类似图像,声音这样的大型数据对象,LOB数据对象可以是二进制数据也可以是字符数据,其最大长度不超过4GLOB数据类型支持任意访问方式,LONG只支持顺序访问方式。LOB存储在一个单独的位置上,同时一个"LOB定位符"(LOB locator)存储在原始的表中,该定位符是一个指向实际数据的指针。在PL/SQL中操作LOB数据对象使用ORACLE提供的包DBMS_LOB.LOB数据类型可分为以下四类:

  . BFILE
  . BLOB
  . CLOB
  . NCLOB

  操作符

  与其他程序设计语言相同,PL/SQL有一系列操作符。操作符分为下面几类:

  . 算术操作符
  . 关系操作符
  . 比较操作符
  . 逻辑操作符

  算术操作符如表4所示

operator

operation

+

-

/

*

**

乘方


  关系操作符主要用于条件判断语句或用于where子串中,关系操作符检查条件和结果是否为truefalse,5PL/SQL中的关系操作符

operator

operation

<

小于操作符

<=

小于或等于操作符

>

大于操作符

>=

大于或等于操作符

=

等于操作符

!=

不等于操作符

<>

不等于操作符

:=

赋值操作符


  表6 显示的是比较操作符

operator

operation

IS NULL

如果操作数为NULL返回TRUE

LIKE

比较字符串值

BETWEEN

验证值是否在范围之内

IN

验证操作数在设定的一系列值中


  表7.8显示的是逻辑操作符

operator

operation

AND

两个条件都必须满足

OR

只要满足两个条件中的一个

NOT

取反


  执行部分

  执行部分包含了所有的语句和表达式,执行部分以关键字BEGIN开始,以关键字EXCEPTION结束,如果EXCEPTION不存在,那么将以关键字END结束。分号分隔每一条语句,使用赋值操作符:=SELECT INTOFETCH INTO给每个变量赋值,执行部分的错误将在异常处理部分解决,在执行部分中可以使用另一个PL/SQL程序块,这种程序块被称为嵌套块

  所有的SQL数据操作语句都可以用于执行部分,PL/SQL块不能再屏幕上显示SELECT语句的输出。SELECT语句必须包括一个INTO子串或者是游标的一部分,执行部分使用的变量和常量必须首先在声明部分声明,执行部分必须至少包括一条可执行语句,NULL是一条合法的可执行语句,事物控制语句COMMITROLLBACK可以在执行部分使用,数据定义语言(Data Definition language)不能在执行部分中使用,DDL语句与EXECUTE IMMEDIATE一起使用或者是DBMS_SQL调用。

  执行一个PL/SQL

  SQL*PLUS中匿名的PL/SQL块的执行是在PL/SQL块后输入/来执行,如下面的例子所示:

1declare 
2 v_comm_percent constant number:=10;
3begin
4 update emp
5 set comm=sal*v_comm_percent
6 where deptno=10;
7 end
8


  命名的程序与匿名程序的执行不同,执行命名的程序块必须使用execute关键字:

1create or replace procedure update_commission
2 (v_dept in number,v_pervent in number default 10is 
3begin
4 update emp
5 set comm=sal*v_percent
6 where deptno=v_dept;
7end
8


SQL>/

Procedure created

SQL>execute update_commission(10,15);

PL/SQL procedure successfully completed.

SQL>


  如果在另一个命名程序块或匿名程序块中执行这个程序,那么就不需要EXECUTE关进字。

 1declare
 2 v_dept number;
 3begin
 4 select a.deptno
 5 into v_dept
 6 from emp a
 7 where job='PRESIDENT'
 8 update_commission(v_dept);
 9end
10

SQL>/
 PL/SQL procedure successfully completed
SQL>

 

控制结构

  控制结构控制PL/SQL程序流程的代码行,PL/SQL支持条件控制和循环控制结构。

  语法和用途

   IF..THEN

  语法:

1IF condition THEN
2 Statements 1;
3 Statements 2;
4 .
5END IF


  IF语句判断条件condition是否为TRUE,如果是,则执行THEN后面的语句,如果conditionfalseNULL则跳过THENEND IF之间的语句,执行END IF后面的语句。

  IF..THEN...ELSE

  语法:

IF condition THEN
 Statements 
1;
 Statements 
2;
 .
ELSE
 Statements 
1;
 Statements 
2;
 .
END IF


  如果条件conditionTRUE,则执行THENELSE之间的语句,否则执行ELSEEND IF之间的语句。

  IF 可以嵌套,可以在IF IF ..ELSE语句中使用IFIF..ELSE语句。

if (a>b) and (a>c) then
  g:=a;
else
  g:=b;
  if c>g then
   g:=c;
  end if
end if


  IF..THEN..ELSIF

  语法:

IF condition1 THEN
 statement1;
ELSIF condition2 THEN
 statement2;
ELSIF condition3 THEN
 statement3;
ELSE
 statement4;
END IF;
 statement5;


  如果条件condition1TRUE则执行statement1,然后执行statement5,否则判断condition2是否为TRUE,若为TRUE则执行statement2,然后执行statement5,对于condition3也是相同的,如果condition1condition2condition3都不成立,那么将执行statement4,然后执行statement5

  循环控制

  循环控制的基本形式是LOOP语句,LOOPEND LOOP之间的语句将无限次的执行。LOOP语句的语法如下:

  LOOP
   statements;
  END LOOP

  LOOPEND LOOP之间的语句无限次的执行显然是不行的,那么在使用LOOP语句时必须使用EXIT语句,强制循环结束,例如:

X:=100;
LOOP
 X:=X+10;
 IF X>1000 THEN
  EXIT;
 END IF
END LOOP;
Y:=X;


  此时Y的值是1010.

  EXIT WHEN语句将结束循环,如果条件为TRUE,则结束循环。

X:=100;
LOOP
X:=X+10;
EXIT WHEN X>1000;
X:=X+10;
END LOOP;
Y:=X;


  WHILE..LOOP

  WHILE..LOOP有一个条件与循环相联系,如果条件为TRUE,则执行循环体内的语句,如果结果为FALSE,则结束循环。

X:=100;
WHILE X<=1000 LOOP
 X:=X+10;
END LOOP;
Y=X;


  FOR...LOOP

  语法:

FOR counter IN [REVERSE] start_range....end_range LOOP
statements;
END LOOP;


  LOOPWHILE循环的循环次数都是不确定的,FOR循环的循环次数是固定的,counter是一个隐式声明的变量,他的初始值是start_range,第二个值是start_range+1,直到end_range,如果start_range等于end _range,那么循环将执行一次。如果使用了REVERSE关键字,那么范围将是一个降序。

X:=100;
FOR v_counter in 1..10 loop
x:=x+10;

end loop
y:=x;


  如果要退出for循环可以使用EXIT语句。

  标签

  用户可以使用标签使程序获得更好的可读性。程序块或循环都可以被标记。标签的形式是<>

  标记程序块

<>
[DECLARE]
... ... ...
BEGIN
........
[EXCEPTION]
.......
END label_name


  标记循环

<>
LOOP
.........
<>
loop
..........
<>
loop
....

EXIT outer_loop WHEN v_condition=0;
end loop innermost_loop;
..........
END LOOP inner_loop;
END LOOP outer_loop;


  GOTO语句

  语法:

  GOTO LABEL;

  执行GOTO语句时,控制会立即转到由标签标记的语句。PL/SQL中对GOTO语句有一些限制,对于块、循环、IF语句而言,从外层跳转到内层是非法的。

X =100;
FOR V_COUNTER IN 1..10 LOOP
 IF V_COUNTER =4 THEN
  GOTO end_of_loop
 END IF
 X:=X+10;
 <>
 NULL
END LOOP

Y:=X;


  注意:NULL是一个合法的可执行语句。

  嵌套

  程序块的内部可以有另一个程序块这种情况称为嵌套。嵌套要注意的是变量,定义在最外部程序块中的变量可以在所有子块中使用,如果在子块中定义了与外部程序块变量相同的变量名,在执行子块时将使用子块中定义的变量。子块中定义的变量不能被父块引用。同样GOTO语句不能由父块跳转道子块中,反之则是合法的。

OUTER BLOCK
DECLARE
 A_NUMBER INTEGER
 B_NUMBER INTEGER
BEGIN
 --A_NUMBER and B_NUMBER are available here
 <>
 DECLARE
 C_NUMBER INTEGER
 B_NUMBER NUMBER(20)
BEGIN
 C_NUMBER:=A_NUMBER;
 C_NUMBER=OUTER_BLOCK.B_NUMBER;
END SUB_BLOCK;
END OUT_BLOCK;


  小结

  我们在这篇文章中介绍了PL/SQL的基础语法以及如何使用PL/SQL语言设计和运行PL/SQL程序块,并将PL/SQL程序整合到Oracle服务器中,虽然PL/SQL程序作为功能块嵌入Oracle数据库中,但PL/SQLORACLE数据库的紧密结合使得越来越多的Oracle数据库管理员和开发人员开始使用PL/SQL

合数据


PL/SQL
有两种复合数据结构:记录和集合。记录由不同的域组成,集合由不同的元素组成。在本文中我们将讨论记录和集合的类型、怎样定义和使用记录和集合。

  PL/SQL 记录

  记录是PL/SQL的一种复合数据结构,scalar数据类型和其他数据类型只是简单的在包一级进行预定义,但复合数据类型在使用前必须被定义,记录之所以被称为复合数据类型是因为他由域这种由数据元素的逻辑组所组成。域可以是scalar数据类型或其他记录类型,它与c语言中的结构相似,记录也可以看成表中的数据行,域则相当于表中的列,在表和虚拟表(视图或查询)中非常容易定义和使用,行或记录中的每一列或域都可以被引用或单独赋值,也可以通过一个单独的语句引用记录所有的域。在存储过程或函数中记录也可能有参数。

  创建记录

  在PL/SQL中有两种定义方式:显式定义和隐式定义。一旦记录被定义后,声明或创建定义类型的记录变量,然后才是使用该变量。隐式声明是在基于表的结构或查询上使用%TYPE属性,隐式声明是一个更强有力的工具,这是因为这种数据变量是动态创建的。

  显式定义记录

  显式定义记录是在PL/SQL程序块中创建记录变量之前在声明部分定义。使用type命令定义记录,然后在创建该记录的变量。语法如下:

TYPE record_type IS RECORD (field_definition_list);


  field_definition_list是由逗号分隔的列表。

  域定义的语法如下:

field_name data_type_and_size [NOT NULL][{:=|DEFAULT} default_value]


  域名必须服从与表或列的命名规则相同的命名规则。下面我们看一个例子:

DELCARE
TYPE stock_quote_rec IS RECORD
(symbol stock.symbol%TYPE
,bid NUMBER(10,4)
,ask NUMBER(10,4)
,volume NUMBER NOT NULL:=0
,exchange VARCHAR2(6) DEFAULT 'NASDAQ'
);

real_time_quote stock_quote_rec;
variable


  域定义时的%TYPE属性用于引用数据库中的表或视图的数据类型和大小,而在此之前程序不知道类型和大小。在上面的例子中记录域在编译时将被定义为与列SYMBOL相同的数据类型和大小,当代码中要使用来自数据库中的数据时,在变量或域定义中最好使用%TYPE来定义。

  隐式定义记录

  隐式定义记录中,我们不用描述记录的每一个域。这是因为我们不需要定义记录的结构,不需要使用TYPE语句,相反在声明记录变量时使用%ROWTYPE命令定义与数据库表,视图,游标有相同结构的记录,与TYPE命令相同的是它是一种定义获得数据库数据记录的好方法。

DECLARE

accounter_info accounts%ROWTYPR;

CURSOR xactions_cur(acct_no IN VARCHAR2) IS
SELECT action,timestamp,holding
FROM portfolios
WHERE account_nbr='acct_no'
;
xaction_info xactions_cur%ROWTYPE;
variable


  有一些PL/SQL指令在使用隐式定义记录时没有使用%ROWTYPE属性,比如游标FOR循环或触发器中的:old:new记录。

DELCARE

CURSOR xaction_cur IS
SELECT action,timeamp,holding
FROM portfolios
WHERE account_nbr='37'
;

BEGIN
FOR xaction_rec in xactions_cur
LOOP
IF xactions_rec.holding='ORCL'
THEN
notify_shareholder;
END IF;
END LOOP;

使用记录

  用户可以给记录赋值、将值传递给其他程序。记录作为一种复合数据结构意味作他有两个层次可用。用户可以引用整个记录,使用select intofetch转移所有域,也可以将整个记录传递给一个程序或将所有域的值赋给另一个记录。在更低的层次,用户可以处理记录内单独的域,用户可以给单独的域赋值或者在单独的域上运行布尔表达式,也可以将一个或更多的域传递给另一个程序。

  引用记录

  记录由域组成,访问记录中的域使用点(.)符号。我们使用上面的例子看看

DELCARE
TYPE stock_quote_rec IS RECORD
(symbol stock.symbol%TYPE
,bid NUMBER(10,4)
,ask NUMBER(10,4)
,volume NUMBER NOT NULL:=0
,exchange VARCHAR2(6) DEFAULT 'NASDAQ'
);

TYPE detailed_quote_rec IS RECORD
(quote stock_quote_rec
,timestamp date
,bid_size NUMBER
,ask.size NUMBER
,last_tick VARCHAR2(4)
);

real_time_detail detail_quote_rec;

BEGIN

real_time_detail.bid_size:=1000;
real_time_detail.quote.volume:=156700;
log_quote(real_time_detail.quote);


  给记录赋值

  给记录或记录中的域赋值的方法有几种,可以使用SELECT INTOFETCH给整个记录或单独的域赋值, 可以将整个记录的值赋给其他记录,也可以通过给每个域赋值来得到记录,以下我们通过实例讲解每一种赋值方法。

  1、使用SELECT INTO

  使用SELECT INTO给记录赋值要将记录或域放在INTO子串中,INTO子串中的变量与SELECT中列的位置相对应。

  例:

DECLARE

stock_info1 stocks%ROWTYPE;
stock_info2 stocks%ROWTYPE;

BEGIN

SELECT symbol,exchange
INTO stock_info1.symbol,stock_info1.exchange
FROM stocks
WHERE symbol='ORCL';

SELECT * INTO stock_info2 FROM stocks
WHERE symbol='ORCL';


  2、使用FETCH

  如果SQL语句返回多行数据或者希望使用带参数的游标,那么就要使用游标,这种情况下使用FETCH语句代替INSTEAD INTO是一个更简单、更有效率的方法,但在安全性较高的包中FETCH的语法如下:

FETCH cursor_name INTO variable;


  我们改写上面的例子:

DECLARE
CURSOR stock_cur(symbol_in VARCHAR2) IS
SELECT symbol,exchange,begin_date
FROM stock
WHERE symbol=UPPER(symbol_in);

stock_info stock_cur%ROWTYPE

BEGIN
OPEN stock_cur('ORCL');
FETCH stock_cur INTO stock_info;


  使用赋值语句将整个记录复制给另一个记录是一项非常有用的技术,不过记录必须精确地被声明为相同的类型,不能是基于两个不同的TYPE语句来获得相同的结构。

  例:

DECLARE

TYPE stock_quote_rec 
IS RECORD
(symbol stocks.symbol
%TYPE
,bid 
NUMBER(10,4)
,ask 
number(10,4)
,volume 
NUMBER
);

TYPE stock_quote_too 
IS RECORD
(symbol stocks.symbol
%TYPE
,bid 
NUMBER(10,4)
,ask 
number(10,4)
,volume 
NUMBER
);

 

--这两个记录看上去是一样的,但实际上是不一样的
stock_one stocks_quote_rec;
stock_two stocks_quote_rec; 
--这两个域有相同的数据类型和大小

stock_also stock_rec_too;
--与stock_quote_rec是不同的数据类型 
BEGIN
stock_one.symbol:
='orcl';
stock_one.volume:
=1234500;
stock_two:
=stock_one;--正确
syock_also:=stock_one;--错误,数据类型错误

stock_also.symbol:
=stock_one.symbol;
stock_also.volume:
=stock_one.volume; 

 


 记录不能用于INSERT语句和将记录直接用于比较,下面两种情况是错误的:

   INSERT INTO stocks VALUES (stock_record);

  和

   IF stock_rec1>stock_rec2 THEN

  要特别注意考试中试题中有可能用%ROWTYPE来欺骗你,但这是错误的,记住这一点。还有可能会出现用记录排序的情况,ORACLE不支持记录之间的直接比较。对于记录比较,可以采用下面的两个选择:

  . 设计一个函数,该函数返回scalar数据类型,使用这个函数比较记录,如

IF sort_rec(stock_one)>sort_rec(stock_two) THEN

  . 可以使用数据库对象,数据库对象可以使用ordermap方法定义,允许oracle对复合数据类型进行比较。关于数据库对象的讨论已经超越了本文的范围,要详细了解数据库对象,可以查阅oracle手册。

PL/SQL集合

  集合与其他语言中的数组相似,在ORACLE7.3及以前的版本中只有一种集合称为PL/SQL表,这种类型的集合依然保留,就是索引(INDEX_BY)表,与记录相似,集合在定义的时候必须使用TYPE语句,然后才是创建和使用这种类型的变量。

  集合的类型
  PL/SQL有三种类型的集合

  . Index_by
  . 嵌套表
  . VARRAY

  这三种类型的集合之间由许多差异,包括数据绑定、稀疏性(sparsity)、数据库中的存储能力都不相同。绑定涉及到集合中元素数量的限制,VARRAY集合中的元素的数量是有限,Index_by和嵌套表则是没有限制的。稀疏性描述了集合的下标是否有间隔,Index_by表总是稀疏的,如果元素被删除了嵌套表可以是稀疏的,但VARRAY类型的集合则是紧密的,它的下标之间没有间隔。

  Index_by表不能存储在数据库中,但嵌套表和VARRAY可以被存储在数据库中。
  虽然这三种类型的集合有很多不同之处,但他们也由很多相似的地方:

   . 都是一维的类似数组的结构
   . 都有内建的方法
   . 访问由点分隔

  Index_by

  Index_by表集合的定义语法如下:

TYPE type_name IS TABLE OF element_type [NOT NULL] INDEX
BY BINARY_INTERGET;

  这里面重要的关键字是INDEX BY BINARY_INTERGET,没有这个关键字,那么集合将是一个嵌套表,element_type可以是任何合法的PL/SQL数据类型,包括:PLS/INTEGERSIGNTYPE、和BOOLEAN其他的集合类型对数据库的数据类型都有限制,但Index_by表不能存储在数据库中,所以没有这些限制。

  一旦定义了index_by表,就可以向创建其他变量那样创建index_by表的变量:

 

DECLARE 
TYPE symbol_tab_typ 
IS TABLE OF VARCHAR2(5INDEX BY BINARY_INTEGER;
symbol_tab symbol_tab_typ;
BEGIN
 

  嵌套表

  嵌套表非常类似于Index_by表,创建的语法也非常相似。使用TYPE语句,只是没有INDEX BY BINARY_INTEGER子串。

  TYPE type_name IS TABLE OF element_type [NOT NULL]

  NOT NULL选项要求集合所有的元素都要有值,element_type可以是一个记录,但是这个记录只能使用标量数据类型字段以及只用于数据库的数据类型(不能是PLS_INTEGER,BOOLEANSIGNTYPE)。

  嵌套表和VARRAY都能作为列存储在数据库表中,所以集合自身而不是单个的元素可以为NULL,ORACLE称这种整个集合为NULL的为"自动设置为NULL(atomically NULL)"以区别元素为NULL的情况。当集合为NULL时,即使不会产生异常,用户也不能引用集合中的元素。用户可以使用IS NULL操作符检测集合是否为NULL

  存储在一个数据库中的嵌套表并不与表中的其它数据存放在同一个数据块中,它们实际上被存放在第二个表中。正如没有order by子句select语句不能保证返回任何有顺序的数据,从数据库中取回的嵌套表也不保证元素的顺序。由于集合数据是离线存储的,对于大型集合嵌套表是一个不错的选择。

  VARRAY

  VARRAY或数据变量都有元素的限制。想起他集合一样VARRAY定义仍然使用TYPE语句,但关键字VARRAYVARRYING ARRAY告诉ORACLE这是一个VARRAY集合。

TYPE type_name IS [VARRAY|VARYING ARRAY] (max_size) OF
element_type [NOT NULL]

  max_size是一个整数,用于标示VARRAY集合拥有的最多元素数目。VARRAY集合的元素数量可以低于max_size,但不能超过max_sizeelement_type是一维元素的数据类型,如果element_type是记录,那么这个记录只能使用标量数据字段(与嵌套标相似)。NOT NULL子串表示集合中的每一个元素都必须有值。

  与嵌套表相似,VARRAY能够自动为NULL,可以使用IS NULL操作符进行检测。与嵌套表不同的是,当VARRAY存储在数据库中时与表中的其他数据存放在同一个数据块中。正象列的排序保存在表的SELECT*中一样元素的顺序保存在VARRAY中。同样由于集合是在线存储的,VARRAY很适合于小型集合。

使用集合
  象记录一样,集合可以在两个层面上使用:

   . 操作整个集合
   . 访问集合中的单个元素

  第一种情况使用集合名,第二种情况使用下标:

   collection(subscript)

  index_by表的下标是两为的整数,可以为正也可以为负,范围是:-2147483647--2147483647。嵌套表和VARRAY表示元素在集合中的位置,用户很难灵活设计下标,这是因为:

   . 嵌套表开始是紧密的(相对于疏松)

   . VARRAY始终保持紧密

   . 这两种集合的下标都由1开始

  初始化、删除、引用集合

  使用集合之前必须要初始化,对于Index_by表初始化是自动进行的,但是对于嵌套表和VARRAY就必须使用内建的构造函数。如果重新调用,嵌套表和VARRAY自动置NULL,这不只是元素置NULL,而是整个集合置NULL。给集合内的元素赋值需要使用下标符号。将一个集合的值赋给另一个集合,只需要简单的使用赋值操作符。

  Index_by集合初始化是最简单的,只要涉及其中的一个元素集合就被初始化了。

  例: 

DECLARE

TYPE symbol_tab_typ 
IS TABLE OF VARCHAR2(5INDEX BY BINARY_INTEGER;
TYPE account_tab_typ 
IS TABLE OF account%ROWTYPE INDEX BY BINARY_INTEGER;
symbol_tab symbol_tab_typ;
account_tab account_tab_typ;
new_acct_tab account_tab_typ;

BEGIN
--初始化集合元素147和-3
SELECT * INTO account_tab(147)
FROM accounts WHERE account_nbr=147;

SELECT * INTO account_tab(-3)
FROM accounts WHERE account_nbr=3003;

IF account_tab(147).balance<500 THEN
chang_maintenance_fee(
147);
END IF

new_acct_tab:
=account_tab;
symbol_tab(
1):="ORCL"; 
symbol_tab(
2):="CSCO"; 
symbol_tab(
3):="SUNM";

publish_portfolio(symbol_tab);

  嵌套表和VARRAY由构造函数初始化,构造函数和集合的名字相同,同时有一组参数,每个参数对应一个元素,如果参数为NULL,那么对应的元素就被初始化为NULL,如果创建了元素,但没有填充数据,那么元素将保持null值,可以被引用,但不能保持数据。如果元素没有初始化,那么就不能引用该元素。

  例:

DECLARE 

TYPE stock_list 
IS TABLE OF stock.symbol%TYPE;
TYPE top10_list 
IS VARRAY (10OF stocks.symbol%TYPE;
biotech_stocks stock_list;
tech_10 top10_list;

BEGIN
--非法,集合未初始化。
biotech_stocks(1):='AMGN';
IF biotech_stocks IS NULL THEN
--初始化集合
biotech_stocks:=('AMGN','BGEN',IMCL','GERN',CRA');
END IF;
tech_10:
=top10_list('ORCL',CSCO','MSFT','INTC','SUNW','IBM',NULL,NULL);
IF tech_10(7) IS NULL THEN
tech_10(7):=
'CPQ';
END
tech_10(8):=
'DELL';

  在这个例子中,嵌套表BIOTECH_STOCKS初始化有5个元素,VARRAY tech_10集合最多能有10 个元素,但构造函数只创建了8个元素,其中还有两个元素是NULL值,并程序中给他们赋值。

  初始化基于记录的集合,就必须将记录传递给构造函数,注意不能只是简单的将记录的域传递给构造函数。

  例:

DECLARE 

TYPE stock_quote_rec 
IS RECORD
(symbol stock.symbol
%TYPE
,bid 
NUMBER(10,4)
,ask 
NUMBER(10,4)
,volume 
NUMBER NOT NULL:=0
);
TYPE stock_tab_typ 
IS TABLE OF stock_quote_rec;
quote_list stock_tab_typ;
single_quote stock_quote_rec;

BEGIN
single_quote.symbol:
='OPCL';
single_quote.bid:
=100;
single_quote.ask:
=101;
single_quote.volume:
=25000;
--合法
quote_list:=stock_tab_typ(single_quote);
--不合法
quote_list:=stock_tab_typ('CSCO',75,76,3210000);
DBMS_OUTPUT.LINE(quote_list(
1).bid);

集合的方法

  除了构造函数外,集合还有很多内建函数,这些函数称为方法。调用方法的语法如下:

   collection.method

  下表中列出oracle中集合的方法

方法

描述

使用限制

COUNT

返回集合中元素的个数

 

DELETE

删除集合中所有元素

 

DELETE()

删除元素下标为x的元素,如果xnull,则集合保持不变

VARRAY非法

DELETE(,)

删除元素下标从XY的元素,如果X>Y集合保持不变

VARRAY非法

EXIST()

如果集合元素x已经初始化,则返回TRUE, 否则返回FALSE

 

EXTEND

在集合末尾添加一个元素

Index_by非法

EXTEND()

在集合末尾添加x个元素

Index_by非法

EXTEND(,)

在集合末尾添加元素nx个副本

Index_by非法

FIRST

返回集合中的第一个元素的下标号,对于VARRAY集合始终返回1

 

LAST

返回集合中最后一个元素的下标号, 对于VARRAY返回值始终等于COUNT.

 

LIMIT

返回VARRY集合的最大的元素个数,对于嵌套表和对于嵌套表和Index_bynull

Index_by集合无用

NEXT()

返回在元素x之后及紧挨着它的元素的值,如果该元素是最后一个元素,则返回null.

 

PRIOR()

返回集合中在元素x之前紧挨着它的元素的值,如果该元素是第一个元素,则返回null

 

TRIM

从集合末端开始删除一个元素

对于index_by不合法

TRIM()

从集合末端开始删除x个元素

index_by不合法

  关于集合之间的比较

  集合不能直接用于比较,要比较两个集合,可以设计一个函数,该函数返回一个标量数据类型。

IF stock_list1>stock_list2 ----非法
IF sort_collection(stock_list1)>sort_collection(stock_list2) THEN --
合法

  但可以比较在集合内的两个元素。

行函数和

函数是一种有零个或多个参数并且有一个返回值的程序。在SQLOracle内建了一系列函数,这些函数都可被称为SQLPL/SQL语句,函数主要分为两大类:

   单行函数

   组函数

  本文将讨论如何利用单行函数以及使用规则。

  SQL中的单行函数

  SQLPL/SQL中自带很多类型的函数,有字符、数字、日期、转换、和混合型等多种函数用于处理单行数据,因此这些都可被统称为单行函数。这些函数均可用于SELECT,WHEREORDER BY等子句中,例如下面的例子中就包含了TO_CHAR,UPPER,SOUNDEX等单行函数。

SELECT ename,TO_CHAR(hiredate,'day,DD-Mon-YYYY')
FROM emp
Where UPPER(ename) Like 'AL%'
ORDER BY SOUNDEX(ename)


  单行函数也可以在其他语句中使用,如updateSET子句,INSERTVALUES子句,DELETWHERE子句,认证考试特别注意在SELECT语句中使用这些函数,所以我们的注意力也集中在SELECT语句中。

  NULL和单行函数

  在如何理解NULL上开始是很困难的,就算是一个很有经验的人依然对此感到困惑。NULL值表示一个未知数据或者一个空值,算术操作符的任何一个操作数为NULL值,结果均为提个NULL,这个规则也适合很多函数,只有CONCAT,DECODE,DUMP,NVL,REPLACE在调用了NULL参数时能够返回非NULL值。在这些中NVL函数时最重要的,因为他能直接处理NULL值,NVL有两个参数:NVL(x1,x2),x1x2都式表达式,当x1null时返回X2,否则返回x1

  下面我们看看emp数据表它包含了薪水、奖金两项,需要计算总的补偿

column name emp_id salary bonus

key type pk
nulls/unique nn,u nn
fk table
datatype number number number
length 11.2 11.2


  不是简单的将薪水和奖金加起来就可以了,如果某一行是null值那么结果就将是null,比如下面的例子:

update emp
set salary=(salary+bonus)*1.1


  这个语句中,雇员的工资和奖金都将更新为一个新的值,但是如果没有奖金,即 salary + null,那么就会得出错误的结论,这个时候就要使用nvl函数来排除null值的影响。
所以正确的语句是:

update emp
set salary=(salary+nvl(bonus,0)*1.1

单行字符串函数

  单行字符串函数用于操作字符串数据,他们大多数有一个或多个参数,其中绝大多数返回字符串

  ASCII()
  c1是一字符串,返回c1第一个字母的ASCII码,他的逆函数是CHR()

SELECT ASCII('A') BIG_A,ASCII('z') BIG_z FROM emp

BIG_A BIG_z
65 122


  CHR(i)[NCHAR_CS]
  i是一个数字,函数返回十进制表示的字符

select CHR(65),CHR(122),CHR(223) FROM emp

CHR65 CHR122 CHR223
A z B


  CONCAT(,)
  c1,c2均为字符串,函数将c2连接到c1的后面,如果c1null,将返回c2.如果c2null,则返回c1,如果c1c2都为null,则返回null。他和操作符||返回的结果相同

select concat('slobo ','Svoboda') username from dual

username

slobo Syoboda


  INITCAP()
  c1为一字符串。函数将每个单词的第一个字母大写其它字母小写返回。单词由空格,控制字符,标点符号限制。

select INITCAP('veni,vedi,vici') Ceasar from dual

Ceasar

Veni,Vedi,Vici


  INSTR(,[,i[,]])
  c1,c2均为字符串,i,j为整数。函数返回c2c1中第j次出现的位置,搜索从c1的第i个字符开始。当没有发现需要的字符时返回0,如果i为负数,那么搜索将从右到左进行,但是位置的计算还是从左到右,ij的缺省值为1.

select INSTR('Mississippi','i',3,3) from dual

INSTR('MISSISSIPPI','I',3,3)

11

select INSTR('Mississippi','i',-2,3) from dual

INSTR('MISSISSIPPI','I',3,3)

2


  INSTRB(,[,i[,j])
  与INSTR()函数一样,只是他返回的是字节,对于单字节INSTRB()等于INSTR()

  LENGTH()
  c1为字符串,返回c1的长度,如果c1null,那么将返回null值。

select LENGTH('Ipso Facto') ergo from dual

ergo

10


  LENGTHb()
  与LENGTH()一样,返回字节。

  lower()
  返回c的小写字符,经常出现在where子串中

select LOWER(colorname) from itemdetail WHERE LOWER(colorname) LIKE '%white%'

COLORNAME

Winterwhite


  LPAD(,i[,])
  c1,c2均为字符串,i为整数。在c1的左侧用c2字符串补足致长度i,可多次重复,如果i小于c1的长度,那么只返回i那么长的c1字符,其他的将被截去。c2的缺省值为单空格,参见RPAD

select LPAD(answer,7,'') padded,answer unpadded from question;

PADDED UNPADDED

Yes Yes
NO NO
Maybe maybe


  LTRIM(,)
  把c1中最左边的字符去掉,使其第一个字符不在c2中,如果没有c2,那么c1就不会改变。

select LTRIM('Mississippi','Mis') from dual

LTR

ppi


  RPAD(,i[,])
  在c1的右侧用c2字符串补足致长度i,可多次重复,如果i小于c1的长度,那么只返回i那么长的c1字符,其他的将被截去。c2的缺省值为单空格,其他与LPAD相似

  RTRIM(,)
  把c1中最右边的字符去掉,使其第后一个字符不在c2中,如果没有c2,那么c1就不会改变。

  REPLACE(,[,])
  c1,c2,c3都是字符串,函数用c3代替出现在c1中的c2后返回。

select REPLACE('uptown','up','down') from dual

REPLACE

downtown


  STBSTR(,i[,])
  c1为一字符串,i,j为整数,从c1的第i位开始返回长度为j的子字符串,如果j为空,则直到串的尾部。

select SUBSTR('Message',1,4) from dual

SUBS

Mess


  SUBSTRB(,i[,])
  与SUBSTR大致相同,只是I,J是以字节计算。

  SOUNDEX()
  返回与c1发音相似的词

select SOUNDEX('dawes') Dawes SOUNDEX('daws') Daws, SOUNDEX('dawson') from dual

Dawes Daws Dawson

D200 D200 D250


  TRANSLATE(,,)
  将c1中与c2相同的字符以c3代替

select TRANSLATE('fumble','uf','ar') test from dual

TEXT

ramble


  TRIM([[]] from c3)
  将c3串中的第一个,最后一个,或者都删除。

select TRIM(' space padded ') trim from dual

TRIM

space padded


  UPPER()
  返回c1的大写,常出现where子串中

select name from dual where UPPER(name) LIKE 'KI%'

NAME

KING

单行数字函数

  单行数字函数操作数字数据,执行数学和算术运算。所有函数都有数字参数并返回数字值。所有三角函数的操作数和值都是弧度而不是角度,oracle没有提供内建的弧度和角度的转换函数。

  ABS()
  返回n的绝对值

  ACOS()
  反余玄函数,返回-11之间的数。n表示弧度

select ACOS(-1) pi,ACOS(1) ZERO FROM dual

PI ZERO

3.14159265 0


  ASIN()
  反正玄函数,返回-11n表示弧度

  ATAN()
  反正切函数,返回n的反正切值,n表示弧度。

  CEIL()
  返回大于或等于n的最小整数。

  COS()
  返回n的余玄值,n为弧度

  COSH()
  返回n的双曲余玄值,n 为数字。

select COSH(<1.4>) FROM dual

COSH(1.4)

2.15089847


  EXP()
  返回en次幂,e=2.71828183.

  FLOOR()
  返回小于等于N的最大整数。

  LN()
  返回N的自然对数,N必须大于0

  LOG(,)
  返回以n1为底n2的对数

  MOD()
  返回n1除以n2的余数,

  POWER(,)
  返回n1n2次方

  ROUND(,)
  返回舍入小数点右边n2位的n1的值,n2的缺省值为0,这回将小数点最接近的整数,如果n2为负数就舍入到小数点左边相应的位上,n2必须是整数。

select ROUND(12345,-2),ROUND(12345.54321,2) FROM dual

ROUND(12345,-2) ROUND(12345.54321,2)

12300 12345.54


  SIGN()
  如果n为负数,返回-1,如果n为正数,返回1,如果n=0返回0.

  SIN)
  返回n的正玄值,n为弧度。

  SINH()
  返回n的双曲正玄值,n为弧度。

  SQRT()
  返回n的平方根,n为弧度

  TAN)
  返回n的正切值,n为弧度

  TANH()  
  
返回n的双曲正切值,n为弧度
  TRUNC(,)
  返回截尾到n2位小数的n1的值,n2缺省设置为0,当n2为缺省设置时会将n1截尾为整数,如果n2为负值,就截尾在小数点左边相应的位上。

  单行日期函数

  单行日期函数操作DATA数据类型,绝大多数都有DATA数据类型的参数,绝大多数返回的也是DATA数据类型的值。

  ADD_MONTHS(,i)
  返回日期d加上i个月后的结果。i可以使任意整数。如果i是一个小数,那么数据库将隐式的他转换成整数,将会截去小数点后面的部分。

  LAST_DAY()
  函数返回包含日期d的月份的最后一天

  MONTHS_BETWEEN(,)
  返回d1d2之间月的数目,如果d1d2的日的日期都相同,或者都使该月的最后一天,那么将返回一个整数,否则会返回的结果将包含一个分数。

  NEW_TIME(,,)
  d1是一个日期数据类型,当时区tz1中的日期和时间是d时,返回时区tz2中的日期和时间。tz1tz2时字符串。

  NEXT_DAY(,)
  返回日期d后由dow给出的条件的第一天,dow使用当前会话中给出的语言指定了一周中的某一天,返回的时间分量与d的时间分量相同。

select NEXT_DAY('01-Jan-2000','Monday') "1st Monday",NEXT_DAY('01-Nov-2004','Tuesday')+7 "2nd Tuesday") from dual;

1st Monday 2nd Tuesday

03-Jan-2000 09-Nov-2004


  ROUND([,])
  将日期d按照fmt指定的格式舍入,fmt为字符串。

  SYADATE
  函数没有参数,返回当前日期和时间。

  TRUNC([,])
  返回由fmt指定的单位的日期d.

单行转换函数

  单行转换函数用于操作多数据类型,在数据类型之间进行转换。

  CHARTORWID()
  c 使一个字符串,函数将c转换为RWID数据类型。

SELECT test_id from test_case where rowid=CHARTORWID('AAAA0SAACAAAALiAAA')


  CONVERT(,[,])
  c尾字符串,dsetsset是两个字符集,函数将字符串csset字符集转换为dset字符集,sset的缺省设置为数据库的字符集。

  HEXTORAW()
  x16进制的字符串,函数将16进制的x转换为RAW数据类型。

  RAWTOHEX()
  xRAW数据类型字符串,函数将RAW数据类转换为16进制的数据类型。

  ROWIDTOCHAR()
  函数将ROWID数据类型转换为CHAR数据类型。

  TO_CHAR([[,)
  x是一个datanumber数据类型,函数将x转换成fmt指定格式的char数据类型,如果x为日期nlsparm=NLS_DATE_LANGUAGE 控制返回的月份和日份所使用的语言。如果x为数字nlsparm=NLS_NUMERIC_CHARACTERS 用来指定小数位和千分位的分隔符,以及货币符号。

NLS_NUMERIC_CHARACTERS ="dg", NLS_CURRENCY="string"


  TO_DATE([,[,
  c表示字符串,fmt表示一种特殊格式的字符串。返回按照fmt格式显示的c,nlsparm表示使用的语言。函数将字符串c转换成date数据类型。

  TO_MULTI_BYTE()
  c表示一个字符串,函数将c的担子截字符转换成多字节字符。

  TO_NUMBER([,[,)
  c表示字符串,fmt表示一个特殊格式的字符串,函数返回值按照fmt指定的格式显示。nlsparm表示语言,函数将返回c代表的数字。

  TO_SINGLE_BYTE()
  将字符串c中得多字节字符转化成等价的单字节字符。该函数仅当数据库字符集同时包含单字节和多字节字符时才使用

  其它单行函数

  BFILENAME( ,)
  dir是一个directory类型的对象,file为一文件名。函数返回一个空的BFILE位置值指示符,函数用于初始化BFILE变量或者是BFILE列。

  DECODE(,,[,,,[])
  x是一个表达式,m1是一个匹配表达式,xm1比较,如果m1等于x,那么返回r1,否则,xm2比较,依次类推m3,m4,m5....直到有返回结果。

  DUMP(,[,[,[,]]])
  x是一个表达式或字符,fmt表示8进制、10进制、16进制、或则单字符。函数返回包含了有关x的内部表示信息的VARCHAR2类型的值。如果指定了n1,n2那么从n1开始的长度为n2的字节将被返回。

  EMPTY_BLOB()
  该函数没有参数,函数返回 一个空的BLOB位置指示符。函数用于初始化一个BLOB变量或BLOB列。

  EMPTY_CLOB()
  该函数没有参数,函数返回 一个空的CLOB位置指示符。函数用于初始化一个CLOB变量或CLOB列。

  GREATEST()
  exp_list是一列表达式,返回其中最大的表达式,每个表达式都被隐含的转换第一个表达式的数据类型,如果第一个表达式是字符串数据类型中的任何一个,那么返回的结果是varchar2数据类型, 同时使用的比较是非填充空格类型的比较。

  LEAST()
  exp_list是一列表达式,返回其中最小的表达式,每个表达式都被隐含的转换第一个表达式的数据类型,如果第一个表达式是字符串数据类型中的任何一个,将返回的结果是varchar2数据类型, 同时使用的比较是非填充空格类型的比较。

  UID
  该函数没有参数,返回唯一标示当前数据库用户的整数。

  USER
  返回当前用户的用户名

  USERENV()
  基于opt返回包含当前会话信息。opt的可选值为:

  ISDBA    会话中SYSDBA脚色响应,返回TRUE
  SESSIONID  返回审计会话标示符
  ENTRYID   返回可用的审计项标示符
  INSTANCE  在会话连接后,返回实例标示符。该值只用于运行Parallel 服务器并且有 多个实例的情况下使用。
  LANGUAGE  返回语言、地域、数据库设置的字符集。
  LANG    返回语言名称的ISO缩写。
  TERMINAL  为当前会话使用的终端或计算机返回操作系统的标示符。

  VSIZE()
  x是一个表达式。返回x内部表示的字节数。

SQL中的组函数

  组函数也叫集合函数,返回基于多个行的单一结果,行的准确数量无法确定,除非查询被执行并且所有的结果都被包含在内。与单行函数不同的是,在解析时所有的行都是已知的。由于这种差别使组函数与单行函数有在要求和行为上有微小的差异.

  组(多行)函数

  与单行函数相比,oracle提供了丰富的基于组的,多行的函数。这些函数可以在selectselecthaving子句中使用,当用于select子串时常常都和GROUP BY一起使用。

  AVG([{DISYINCT|ALL}])
  返回数值的平均值。缺省设置为ALL.

SELECT AVG(sal),AVG(ALL sal),AVG(DISTINCT sal) FROM scott.emp

AVG(SAL) AVG(ALL SAL) AVG(DISTINCT SAL)

1877.94118 1877.94118 1916.071413


  COUNT({*|DISTINCT|ALL} )
  返回查询中行的数目,缺省设置是ALL,*表示返回所有的行。

  MAX([{DISTINCT|ALL}])
  返回选择列表项目的最大值,如果x是字符串数据类型,他返回一个VARCHAR2数据类型,如果X是一个DATA数据类型,返回一个日期,如果Xnumeric数据类型,返回一个数字。注意distinctall不起作用,应为最大值与这两种设置是相同的。

  MIN([{DISTINCT|ALL}])
  返回选择列表项目的最小值。

  STDDEV([{DISTINCT|ALL}])
  返回选者的列表项目的标准差,所谓标准差是方差的平方根。

  SUM([{DISTINCT|ALL}])
  返回选择列表项目的数值的总和。

  VARIANCE([{DISTINCT|ALL}])
  返回选择列表项目的统计方差。

  GROUP BY给数据分组

  正如题目暗示的那样组函数就是操作那些已经分好组的数据,我们告诉数据库用GROUP BY怎样给数据分组或者分类,当我们在SELECT语句的SELECT子句中使用组函数时,我们必须把为分组或非常数列放置在GROUP BY子句中,如果没有用group by进行专门处理,那么缺省的分类是将整个结果设为一类。

select stat,counter(*) zip_count from zip_codes GROUP BY state;

ST ZIP_COUNT
-- ---------
AK 360
AL 1212
AR 1309
AZ 768
CA 3982


  在这个例子中,我们用state字段分类;如果我们要将结果按照zip_codes排序,可以用ORDER BY语句,ORDER BY子句可以使用列或组函数。

select stat,counter(*) zip_count from zip_codes GROUP BY state ORDER BY COUNT(*) DESC;

ST COUNT(*)
-- --------
NY 4312
PA 4297
TX 4123
CA 3982


  HAVING子句限制分组数据

  现在你已经知道了在查询的SELECT语句和ORDER BY子句中使用主函数,组函数只能用于两个子串中,组函数不能用于WHERE子串中,例如下面的查询是错误的

错误
SELECT sales_clerk,SUN(sale_amount) FROM gross_sales WHERE sales_dept='OUTSIDE' AND SUM(sale_amount)>10000 GROUP BY sales_clerk


  这个语句中数据库不知道SUM()是什么,当我们需要指示数据库对行分组,然后限制分组后的行的输出时,正确的方法是使用HAVING语句:

SELECT sales_clerk,SUN(sale_amount)
FROM gross_sales
WHERE sales_dept='OUTSIDE'
GROUP BY sales_clerk
HAVING SUM(sale_amount)>10000;


  嵌套函数

  函数可以嵌套。一个函数的输出可以是另一个函数的输入。操作数有一个可继承的执行过程。但函数的优先权只是基于位置,函数遵循由内到外,由左到右的原则。嵌套技术一般用于象DECODE这样的能被用于逻辑判断语句IF....THEN...ELSE的函数。
  嵌套函数可以包括在组函数中嵌套单行函数,或者组函数嵌套入单行函数或组函数中。比如下面的例子:

SELECT deptno, GREATEST(COUNT(DISTINCT job),COUNT(DISTINCT mgr) cnt,
COUNT(DISTINCT job) jobs,
COUNT(DISTINCT mgr) mgrs
FROM emp
GROUP BY deptno;

DEPTNO CNT JOBS MGRS
------ --- ---- ----
10 4 4 2
20 4 3 4
30 3 3 2

 

Oracle数据数据象分

Oracle数据库数据对象中最基本的是表和视图,其他还有约束、序列、函数、存储过程、包、触发器等。对数据库的操作可以基本归结为对数据对象的操作,理解和掌握Oracle数据库对象是学习Oracle的捷径。

  表和视图

  Oracle中表是数据存储的基本结构。ORACLE8引入了分区表和对象表,ORACLE8i引入了临时表,使表的功能更强大。视图是一个或多个表中数据的逻辑表达式。本文我们将讨论怎样创建和管理简单的表和视图。

  管理表

  表可以看作有行和列的电子数据表,表是关系数据库中一种拥有数据的结构。CREATE TABLE语句建立表,在建立表的同时,必须定义表名,列,以及列的数据类型和大小。例如:

CREATE TABLE products
  ( PROD_ID NUMBER(4),
   PROD_NAME VAECHAR2(20),
   STOCK_QTY NUMBER(5,3)
  );


  这样我们就建立了一个名为products的表, 关键词CREATE TABLE后紧跟的表名,然后定义了三列,同时规定了列的数据类型和大小。

  在创建表的同时你可以规定表的完整性约束,也可以规定列的完整性约束,在列上普通的约束是NOT NULL,关于约束的讨论我们在以后进行。

  在建立或更改表时,可以给表一个缺省值。缺省值是在增加行时,增加的数据行中某一项值为null时,oracle即认为该值为缺省值。

  下列数据字典视图提供表和表的列的信息:

   . DBA_TABLES
   . DBA_ALL_TABLES
   . USER_TABLES
   . USER_ALL_TABLES
   . ALL_TABLES
   . ALL_ALL_TABLES
   . DBA_TAB_COLUMNS
   . USER_TAB_COLUMNS
   . ALL_TAB_COLUMNS

  表的命名规则

  表名标识一个表,所以应尽可能在表名中描述表,oracle中表名或列名最长可以达30个字符串。表名应该以字母开始,可以在表名中包含数字、下划线、#$等。

  从其它表中建立表

  可以使用查询从基于一个或多个表中建立表,表的列的数据类型和大小有查询结果决定。建立这种形式的表的查询可以选择其他表中所有的列或者只选择部分列。CREATE TABLE语句中使用关键字AS,例如:

SQL>CREATE TABLE emp AS SELECT * FROM employee

TABLE CREATED

SQL> CREATE TABLE Y AS SELECT * FROM X WHERE no=2


  需要注意的是如果查询涉及LONG数据类型,那么CREATE TABLE....AS SELECT....将不会工作。

  更改表定义

  在建立表后,有时候我们可能需要修改表,比如更改列的定义,更改缺省值,增加新列,删除列等等。ORACLE使用ALTER TABLE语句来更改表的定义

  1、增加列

  语法:

ALTER TABLE [schema.] table_name ADD column_definition


  例:

ALTER TABLE orders ADD order_date DATE;

TABLE ALTER


  对于已经存在的数据行,新列的值将是NULL.

  2、更改列

  语法:

ALTER TABLE [schema.] table_name MODIFY column_name new_attributes;


  例:

ALTER TABLE orders MODITY (quantity number(10,3),status varchar2(15));


  这个例子中我们修改了表orders,将STATUS列的长度增加到15,QUANTITY列减小到10,3;

  修改列的规则如下:

   . 可以增加字符串数据类型的列的长度,数字数据类型列的精度。

   . 减少列的长度时,该列应该不包含任何值,所有数据行都为NULL.

   . 改变数据类型时,该列的值必须是NULL.

   . 对于十进制数字,可以增加或减少但不能降低他的精度。

  3、删除数据列

  优化ORACLE数据库,唯一的方法是删除列,重新建立数据库。在ORACLE8i中有很多方法删除列,你可以删除未用数据列或者可以标示该列为未用数据列然后删除。

  删除数据列的语法是:

ALTER TABLE [schema.] table_name DROP {COLUM column_names | (column_names)}[CASCADE CONSTRAINS]


  要注意的是在删除列时关于该列的索引和完整性约束也同时删除。注意关键字CASCADE CONSTRAINS,如果删除的列是多列约束的一部分,那么这个约束条件相对于其他列也同时删除。

  如果用户担心在大型数据库中删除列要花太多时间,可以先将他们标记为未用数据列,标记未用数据列的语法如下:

ALTER TABLE [schema.] table_name SET UNUSED {COLUM column_names | (column_names)}[CASCADE CONSTRAINS]


  这个语句将一个或多个数据列标记为未用数据列,但并不删除数据列中的数据,也不释放占用的磁盘空间。但是,未用数据列在视图和数据字典中并不显示,并且该数据列的名称将被删除,新的数据列可以使用这个名称。基于该数据列的索引、约束,统计等都将被删除。

  删除未用数据列的语句是:

ALTER TABLE [schema.] table_name DROP {UNUSED COLUM | COLUMN CONTINUE}

删除表和更改表名

  删除表非常简单,但它是一个不可逆转的行为。

  语法:

DROP TABLE [schema.] table_name [CASCADE CONSTRAINTS]

  
  删除表后,表上的索引、触发器、权限、完整性约束也同时删除。ORACLE不能删除视图,或其他程序单元,但oracle将标示他们无效。如果删除的表涉及引用主键或唯一关键字的完整性约束时,那么DROP TABLE语句就必须包含CASCADE CONSTRAINTS子串。

  更改表名

  RENAME命令用于给表和其他数据库对象改名。ORACLE系统自动将基于旧表的完整性约束、索引、权限转移到新表中。ORACLE同时使所有基于旧表的数据库对象,比如视图、程序、函数等,为不合法。

  语法:

RENAME old_name TO new_name;


  例:

SQL> RENAME orders TO purchase_orders;

TABLE RENAMED


  截短表

  TRUNCATE命令与DROP命令相似, 但他不是删除整个数据表,所以索引、完整性约束、触发器、权限等都不会被删除。缺省情况下将释放部分表和视图空间,如果用户不希望释放表空间,TRUNCATE语句中要包含REUSE STORAGE子串。TRUNCATE命令语法如下:

TRUNCATE {TABLE|CLUSTER} [schema.] name {DROP|REUSE STORAGE}


  例:

SQL> TRUNCATE TABLE t1;

TABLE truncate.


  管理视图

  视图是一个或多个表中的数据的简化描述,用户可以将视图看成一个存储查询(stored query)或一个虚拟表(virtual table).查询仅仅存储在oracle数据字典中,实际的数据没有存放在任何其它地方,所以建立视图不用消耗其他的空间。视图也可以隐藏复杂查询,比如多表查询,但用户只能看见视图。视图可以有与他所基于表的列名不同的列名。用户可以建立限制其他用户访问的视图。

  建立视图

  CREATE VIEW命令创建视图,定义视图的查询可以建立在一个或多个表,或其他视图上。查询不能有FOR UPDATE子串,在早期的ORACLE8i版本中不支持ORDER BY子串,现在的版本中CREATE VIEW可以拥有ORDER BY子串。

  例:

SQL> CREATE VIEW TOP_EMP AS
SELECT empno EMPLOYEE_ID,ename EMPLOYEE_NAME,salary
FROM emp
WHERE salary >2000


  用户可以在创建视图的同时更改列名,方法是在视图名后立即加上要命名的列名。重新定义视图需要包含OR REPLACE子串。

SQL> CREATE VIEW TOP_EMP
EMPLOYEE_IDEMPLOYEE_NAMESALARY) AS
SELECT empno ,ename ,salary
FROM emp
WHERE salary >2000


  如果在创建的视图包含错误在正常情况下,视图将不会被创建。但如果你需要创建一个带错误的视图必须在CREATE VIEW语句中带上FORCE选项。如:

CREATE FORCE VIEW ORDER_STATUS AS
SELECT * FROM PURCHASE_ORDERS
WHERE STATUS='APPPOVE';

SQL>/

warning :View create with compilation errors


  这样将创建了一个名为ORDER_STATUS的视图,但这样的视图的状态是不合法的,如果以后状态发生变化则可以重新编译,其状态也变成合法的。

  从视图中获得数据

  从视图中获得数据与从表中获得数据基本一样,用户可以在连接和子查询中使用视图,也可以使用SQL函数,以及所有SELECT语句的字串。

  插入、更新、删除数据

  用户在一定的限制条件下可以通过视图更新、插入、删除数据。如果视图连接多个表,那么在一个时间里只能更新一个表。所有的能被更新的列可以在数据字典USER_UPDATETABLE_COLUMNS中查到。

  用户在CREATE VIEW中可以使用了WITH子串。WITH READ ONLY子串表示创建的视图是一个只读视图,不能进行更新、插入、删除操作。WITH CHECK OPTION表示可以进行插入和更新操作,但应该满足WHERE子串的条件。这个条件就是创建视图WHERE子句的条件,比如在上面的例子中用户创建了一个视图TOP_EMP,在这个视图中用户不能插入salary小于2000的数据行。

  删除视图

  删除视图使用DROP VIEW命令。同时将视图定义从数据字典中删除,基于视图的权限也同时被删除,其他涉及到该视图的函数、视图、程序等都将被视为非法。

  例:

DROP VIEW TOP_EMP;

完整性

  完整性约束用于增强数据的完整性,Oracle提供了5种完整性约束:

    Check
    NOT NULL
    Unique
    Primary
    Foreign key

  完整性约束是一种规则,不占用任何数据库空间。完整性约束存在数据字典中,在执行SQLPL/SQL期间使用。用户可以指明约束是启用的还是禁用的,当约束启用时,他增强了数据的完整性,否则,则反之,但约束始终存在于数据字典中。

  禁用约束,使用ALTER语句

ALTER TABLE table_name DISABLE CONSTRAINT constraint_name;


  或

ALTER TABLE policies DISABLE CONSTRAINT chk_gender


  如果要重新启用约束:

ALTER TABLE policies ENABLE CONSTRAINT chk_gender


  删除约束

ALTER TABLE table_name DROP CONSTRAINT constraint_name


  或

ALTER TABLE policies DROP CONSTRAINT chk_gender;


  Check 约束

  在数据列上Check 约束需要 一个特殊的布尔条件或者将数据列设置成TRUE,至少一个数据列的值是NULLCheck约束用于增强表中数据内容的简单的商业规则。用户使用Check约束保证数据规则的一致性。Check约束可以涉及该行同属Check约束的其他数据列但不能涉及其他行或其他表,或调用函数SYSDATE,UID,USER,USERENV。如果用户的商业规则需要这类的数据检查,那么可以使用触发器。Check约束不保护LOB数据类型的数据列和对象、嵌套表、VARRYref等。单一数据列可以有多个Check约束保护,一个Check约束可以保护多个数据列。

  创建表的Check约束使用CREATE TABLE语句,更改表的约束使用ALTER TABLE语句。

  语法:

CONSTRAINT [constraint_name] CHECK (condition);


  Check约束可以被创建或增加为一个表约束,当Check约束保护多个数据列时,必须使用表约束语法。约束名是可选的并且如果这个名字不存在,那么oracle将产生一个以SYS_开始的唯一的名字。

  例:

CREATE TABLE policies
(policy_id NUMBER,
holder_name VARCHAR2(40),
gender VARCHAR2(1) constraint chk_gender CHECK (gender in ('M','F'),
marital_status VARCHAR2(1),
date_of_birth DATE,
constraint chk_marital CHECK (marital_status in('S','M','D','W'))
);


  NOT NULL约束

  NOT NULL约束应用在单一的数据列上,并且他保护的数据列必须要有数据值。缺省状况下,ORACLE允许任何列都可以有NULL值。某些商业规则要求某数据列必须要有值,NOT NULL约束将确保该列的所有数据行都有值。

  例:

CREATE TABLE policies
(policy_id NUMBER,
holder_name VARCHAR2(40) NOT NULL,
gender VARCHAR2(1),
marital_status VARCHAR2(1),
date_of_birth DATE NOT NULL
);


  对于NOT NULLALTER TABLE语句与其他约束稍微有点不同。

ALTER TABLE policies MODIFY holder_name NOT NULL

唯一性约束(Unique constraint)

  唯一性约束可以保护表中多个数据列,保证在保护的数据列中任何两行的数据都不相同。唯一性约束与表一起创建,在唯一性约束创建后,可以使用ALTER TABLE语句修改。

  语法:

column_name data_type CONSTRAINT constraint_name UNIQUE


  如果唯一性约束保护多个数据列,那么唯一性约束要作为表约束增加。语法如下:

CONSTRAINT constraint_name (column) UNIQUE USING INDEX TABLESPACE (tablespace_name) STORAGE (stored clause)


  唯一性约束由一个B-tree索引增强,所以可以在USING子串中为索引使用特殊特征,比如表空间或存储参数。CREATE TABLE语句在创建唯一性约束的同时也给目标数据列建立了一个唯一的索引。

CREATE TABLE insured_autos
(policy_id NUMBER CONSTRAINT pk_policies PRIMARY KEY,
vin VARCHAR2(10),
coverage_begin DATE,
coverage_term NUMBER,
CONSTRAIN unique_auto UNIQUE (policy_id,vin) USING INDEX TABLESPACE index STORAGE (INITIAL 1M NEXT 10M PCTINCREASE 0)
);


  用户可以禁用未以性约束,但他仍然存在,禁用唯一性约束使用ALTER TABLE 语句

ALTER TABLE insured_autos DISABLE CONSTRAIN unique_name;


  删除唯一性约束,使用ALTER TABLE....DROP CONSTRAIN语句

ALTER TABLE insured_autos DROP CONSTRAIN unique_name;


  注意用户不能删除在有外部键指向的表的唯一性约束。这种情况下用户必须首先禁用或删除外部键(foreign key)

  删除或禁用唯一性约束通常同时删除相关联的唯一索引,因而降低了数据库性能。经常删除或禁用唯一性约束有可能导致丢失索引带来的性能错误。要避免这样错误,可以采取下面的步骤:

  1、在唯一性约束保护的数据列上创建非唯一性索引。

  2、添加唯一性约束

  主键(Primary Key)约束

  表有唯一的主键约束。表的主键可以保护一个或多个列,主键约束可与NOT NULL约束共同作用于每一数据列。NOT NULL约束和唯一性约束的组合将保证主键唯一地标识每一行。像唯一性约束一样,主键由B-tree索引增强。

  创建主键约束使用CREATE TABLE语句与表一起创建,如果表已经创建了,可以使用ALTER TABLE语句。

CREATE TABLE policies
(policy_id NUMBER CONSTRAINT pk_policies PRIMARY KEY,
holder_name VARCHAR2(40),
gender VARCHAR2(1),
marital_status VARCHAR2(1),
date_of_birth DATE
);


  与唯一性约束一样,如果主键约束保护多个数据列,那么必须作为一个表约束创建。

CREATE TABLE insured_autos
(policy_id NUMBER,
vin VARCHAR2(40),
coverage_begin DATE,
coverage_term NUMBER,
CONSTRAINT pk_insured_autos PRIMARY KEY (policy_id,vin)
USING INDEX TABLESPACE index
STORAGE (INITIAL 1M NEXT 10M PCTINCREASE 0)
);


  禁用或删除主键必须与ALTER TABLE 语句一起使用

ALTER TABLE policies DROP PRIMARY KEY;


  或

ALTER TABLE policies DISABLE PRIMARY KEY;


  外部键约束(Foreign key constraint)

  外部键约束保护一个或多个数据列,保证每个数据行的数据包含一个或多个null值,或者在保护的数据列上同时拥有主键约束或唯一性约束。引用(主键或唯一性约束)约束可以保护同一个表,也可以保护不同的表。与主键和唯一性约束不同外部键不会隐式建立一个B-tree索引。在处理外部键时,我们常常使用术语父表(parent table)和子表(child table),父表表示被引用主键或唯一性约束的表,子表表示引用主键和唯一性约束的表。

  创建外部键使用CREATE TABLE语句,如果表已经建立了,那么使用ALTER TABLE语句。

CREATE TABLE insured_autos
(policy_id NUMBER CONSTRAINT policy_fk
REFERENCE policies(policy_id
ON DELETE CASCADE,
vin VARCHAR2(40),
coverage_begin DATE,
coverage_term NUMBER,
make VARCHAR2(30),
model VARCHAR(30),
year NUMBER,
CONSTRAIN auto_fk FROEIGN KEY (make,model,year)
REFERENCES automobiles (make,model,year)
ON DELETE SET NULL
);


  ON DELETE子串告诉ORACLE如果父纪录(parent record)被删除后,子记录做什么。缺省情况下禁止在子记录还存在的情况下删除父纪录。

  外部键和NULL

  在外部键约束保护的数据列中NULL值的处理可能产生不可预料的结果。ORACLE 使用ISO standar Match None规则增强外部键约束。这个规则规定如果任何外部键作用的数据列包含有一个NULL值,那么任何保留该键的数据列在父表中没有匹配值。

  比如,在父表AUTOMOBILES中,主键作用于数据列MAKEMODELYEAR上,用户使用的表INSURED_AUTOS有一个外部约束指向AOTOMOBILES,注意在INSURES_AUTOS中有一数据行的MODEL列为NULL值,这一行数据已经通过约束检查,即使MAKE列也没有显示在父表AUTOMOBILES中,如下表:

  表1 AUTOMOBILES

MAKE

MODEL

YEAR

Ford

Taurus

2000

Toyota

Camry

1999


  表2 INSURED_AUTOS

POLICY_ID

MAKE

MODEL

YEAR

576

Ford

Taurus

2000

577

Toyota

Camry

1999

578

Tucker

NULL

1949


  延迟约束检验(Deferred Constraint Checking

  约束检验分两种情况,一种是在每一条语句结束后检验数据是否满足约束条件,这种检验称为立即约束检验(immediately checking,另一种是在事务处理完成之后对数据进行检验称之为延迟约束检验。在缺省情况下Oracle约束检验是立即检验(immediately checking),如果不满足约束将先是一条错误信息,但用户可以通过SET CONSTRAINT语句选择延迟约束检验。语法如下:

SET CONSTRAINT constraint_name|ALL DEFEERRED|IMMEDIATE --;

序列(Sequences

  Oracle序列是一个连续的数字生成器。序列常用于人为的关键字,或给数据行排序否则数据行是无序的。像约束一样,序列只存在于数据字典中。序列号可以被设置为上升、下降,可以没有限制或重复使用直到一个限制值。创建序列使用SET SEQUENCE语句。

CREATE SEQUENCE [schema] sequence KEYWORD


  KEYWORD包括下面的值:

KEYWORD

描述

START WITH

定义序列生成的第一个数字,缺省为1

INCREMENT BY

定义序列号是上升还是下降,对于一个降序的序列INCREMENT BY为负值

MINVALUE

定义序列可以生成的最小值,这是降序序列中的限制值。缺省情况下该值为NOMINVALUE,NOMINVALUE,对于升序为1,对于降序为-10E26.

MAXVALUE

序列能生成的最大数字。这是升序序列中的限制值,缺省的MAXVALUENOMAXVALUE,NOMAXVALUE,对于升序为10E26,对于降序为-1

CYCLE

设置序列值在达到限制值以后可以重复

NOCYCLE

设置序列值在达到限制值以后不能重复,这是缺省设置。当试图产生MAXVALUE+1的值时,将会产生一个异常

CACHE

定义序列值占据的内存块的大小,缺省值为20

NOCACHE

在每次序列号产生时强制数据字典更新,保证在序列值之间没有间隔当创建序列时,START WITH值必须等于或大于MINVALUE


  删除序列使用DROP SEQUENCE语句

DROP SEQUENCE sequence_name


  索引(INDEXES)

  索引是一种可以提高查询性能的数据结构,在这一部分我们将讨论索引如何提高查询性能的。ORACLE提供了以下几种索引:

   B-Tree、哈希(hash)、位图(bitmap)等索引类型
   基于原始表的索引
   基于函数的索引
   域(Domain)索引

  实际应用中主要是B-Tree索引和位图索引,所以我们将集中讨论这两种索引类型。

  B-Tree索引

  B-Tree索引是最普通的索引,缺省条件下建立的索引就是这种类型的索引。B-Tree索引可以是唯一或非唯一的,可以是单一的(基于一列)或连接的(多列)。B-Tree索引在检索高基数数据列(高基数数据列是指该列有很多不同的值)时提供了最好的性能。对于取出较小的数据B-Tree索引比全表检索提供了更有效的方法。但当检查的范围超过表的10%时就不能提高取回数据的性能。正如名字所暗示的那样,B-Tree索引是基于二元树的,由枝干块(branch block)和树叶块(leaf block)组成,枝干块包含了索引列(关键字)和另一索引的地址。树叶块包含了关键字和给表中每个匹配行的ROWID

  位图索引

  位图索引主要用于决策支持系统或静态数据,不支持行级锁定。位图索引可以是简单的(单列)也可以是连接的(多列),但在实践中绝大多数是简单的。位图索引最好用于低到中群集(cardinality)列,在这些列上多位图索引可以与ANDOR操作符结合使用。位图索引使用位图作为键值,对于表中的每一数据行位图包含了TRUE1)、FALSE0)、或NULL值。位图索引的位图存放在B-Tree结构的页节点中。B-Tree结构使查找位图非常方便和快速。另外,位图以一种压缩格式存放,因此占用的磁盘空间比B-Tree索引要小得多。

  同义词(Synonyms

  对另一个数据对象而言同义词是一个别名。public同义词是针对所有用户的,相对而言private同义词则只针对对象拥有者或被授予权限的账户。在本地数据库中同义词可以表示表、视图、序列、程序、函数或包等数据对象,也可以通过链接表示另一个数据库的对象。

  创建同义词语法如下:

CREATE [PUBLIC] SYNONYM synonym_name FOR [schema.] object[@db_link];

  
  例:

CREATE PUBLIC SYNONYM policies FOR poladm.policies@prod;

CREATE SYNONYM plan_table FOR system.plan_table;

程和函数

  过程和函数都以编译后的形式存放在数据库中,函数可以没有参数也可以有多个参数并有一个返回值。过程有零个或多个参数,没有返回值。函数和过程都可以通过参数列表接收或返回零个或多个值,函数和过程的主要区别不在于返回值,而在于他们的调用方式。过程是作为一个独立执行语句调用的:

pay_involume(invoice_nbr,30,due_date);

  函数以合法的表达式的方式调用:

order_volumn:=open_orders(SYSDATE,30);

  创建过程的语法如下:

CREATE [ OR REPLACE] PROCEDURE [schema.]procedure_name
[parameter_lister]
{AS|IS}
declaration_section
BEGIN
executable_section
[EXCEPTION
exception_section]
END [procedure_name]


  每个参数的语法如下:

paramter_name mode datatype [(:=|DEFAULT) value]

  mode有三种形式:INOUTINOUT

  IN表示在调用过程的时候,实际参数的取值被传递给该过程,形式参数被认为是只读的,当过程结束时,控制会返回控制环境,实际参数的值不会改变。

  OUT在调用过程时实际参数的取值都将被忽略,在过程内部形式参数只能是被赋值,而不能从中读取数据,在过程结束后形式参数的内容将被赋予实际参数。

  INOUT这种模式是INOUT的组合;在过程内部实际参数的值会传递给形式参数,形势参数的值可读也可写,过程结束后,形势参数的值将赋予实际参数。

  创建函数的语法和过程的语法基本相同,唯一的区别在于函数有RETUREN子句

CREATE [ OR REPLACE] FINCTION [schema.]function_name
[parameter_list]
RETURN returning_datatype
{AS|IS}
declaration_section
BEGIN
executable_section
[EXCEPTION]
exception_section
END [procedure_name]


  在执行部分函数必须有哟个或多个return语句。

  在创建函数中可以调用单行函数和组函数,例如:

CREATE OR REPLACE FUNCTION my_sin(DegreesIn IN NUMBER)
RETURN NUMBER
IS
pi NUMBER=ACOS(-1);
RadiansPerDegree NUMBER;

BEGIN
RadiansPerDegree=pi/180;
RETURN(SIN(DegreesIn*RadiansPerDegree));
END



  包是一种将过程、函数和数据结构捆绑在一起的容器;包由两个部分组成:外部可视包规范,包括函数头,过程头,和外部可视数据结构;另一部分是包主体(package body),包主体包含了所有被捆绑的过程和函数的声明、执行、异常处理部分。

  打包的PL/SQL程序和没有打包的有很大的差异,包数据在用户的整个会话期间都一直存在,当用户获得包的执行授权时,就等于获得包规范中的所有程序和数据结构的权限。但不能只对包中的某一个函数或过程进行授权。包可以重载过程和函数,在包内可以用同一个名字声明多个程序,在运行时根据参数的数目和数据类型调用正确的程序。

  创建包必须首先创建包规范,创建包规范的语法如下:

CREATE [OR REPLACE] PACKAGE package_name
{AS|IS}
public_variable_declarations |
public_type_declarations |
public_exception_declarations |
public_cursor_declarations |
function_declarations |
procedure_specifications
END [package_name]


  创建包主体使用CREATE PACKAGE BODY语句:

CREATE [OR REPLACE] PACKAGE BODY package_name
{AS|IS}
private_variable_declarations |
private_type_declarations |
private_exception_declarations |
private_cursor_declarations |
function_declarations |
procedure_specifications
END [package_name]


  私有数据结构是那些在包主体内部,对被调用程序而言是不可见的。

  触发器(Triggers)

  触发器是一种自动执行响应数据库变化的程序。可以设置为在触发器事件之前或之后触发或执行。能够触发触发器事件的事件包括下面几种:

  DML事件
  DDL事件
  数据库事件

  DML事件触发器可以是语句或行级触发器。DML语句触发器在触发语句之前或之后触发DML行级触发器在语句影响的行变化之前或之后触发。用户可以给单一事件和类型定义多个触发器,但没有任何方法可以增强多触发器触发的命令。下表列出了用户可以利用的触发器事件:

事件

触发器描述

INSERT

当向表或视图插入一行时触发触发器

UPDATE

更新表或视图中的某一行时触发触发器

DELETE

从表或视图中删除某一行时触发触发器

CREATE

当使用CREATE语句为数据库或项目增加一个对象时触发触发器

ALTER

当使用ALTER语句为更改一个数据库或项目的对象时触发触发器

DROP

当使用DROP语句删除一个数据库或项目的对象时触发触发器

START

打开数据库时触发触发器,在事件后触发

SHUTDOWN

关闭数据库时触发,事件前触发

LOGON

当一个会话建立时触发,事件前触发

LOGOFF

当关闭会话时触发,事件前触发

SERVER

服务器错误发生时触发触发器,事件后触发


  创建触发器的语法如下:

CREATE [OR REPLACE] TRIGGER trigger_name
{before|after|instead of} event
ON {table_or_view_name|DATABASE}
[FOR EACH ROW[WHEN condition]]
trigger_body


  只有DML触发器(INSERTUPDATEDELETE)语句可以使用INSTEAD OF触发器并且只有表的DML触发器可以是BEFOREAFTER触发器。

  象约束一样触发器可以被设置为禁用或启用来关闭或打开他们的执行体(EXECUTE),将触发器设置为禁用或启用使用ALTER TRIGGER语句:

ALTER TRIGGER trigger_name ENABLE;
ALTER TRIGGER trigger_name DISABLE;


  要禁用或启用表的所有触发器,使用ALTER TABLE语句

ALTER TRIGGER table_name DISABLE ALL TRIGGER;
ALTER TRIGGER table_name ENABLE ALL TRIGGER;


  删除触发器使用DROP TRIGGER

DROP TRIGGER trigger_name;


  数据字典

  Oracle数据字典包含了用户数据库的元数据。带下划线的表名称中带OBJ$UET$SOURCE$,这些表是在执行CREATE DATABASE语句期间由sql.bsq脚本创建的,一般情况下用户很少访问这些表。脚本catalog.sql(通常位于$oracle_home/rdbms/admin)在CREATE DATABASE语句之后立即运行,创建数据字典视图。

  数据字典视图大致可以分为三类:

  .前缀为USER_的数据字典视图,包含了用户拥有的对象的信息。

  .前缀为ALL_的数据字典视图,包含了用户当前可以访问的全部对象和权限的信息。

  .前缀为DBA_的数据字典视图,包含了数据库拥有的所有对象和权限的信息。
  在绝大多数数据字典视图中都有象DBA_TABLES,ALL_TABLESUSER_TABLES这样的视图家族。Oracle中有超过100个视图家族,所以要全面介绍这些视图家族是单调乏味的而且没有多大的意义。在下表中列出了最重要和最常用的视图家族,需要注意的是每个视图家族都有一个DBA_,一个ALL_一个USER_视图。

视图家族(View Family)

描述

COL_PRIVS

包含了表的列权限,包括授予者、被授予者和权限

EXTENTS

数据范围信息,比如数据文件,数据段名(segment_name)和大小

INDEXES

索引信息,比如类型、唯一性和被涉及的表

IND_COLUMNS

索引列信息,比如索引上的列的排序方式

OBJECTS

对象信息,比如状态和DDL time

ROLE_PRIVS

角色权限,比如GRANTADMIN选项

SEGMENTS

表和索引的数据段信息,比如tablespacestorage

SEQUECNCES

序列信息,比如序列的cachecycleast_number

SOURCE

除触发器之外的所有内置过程、函数、包的源代码

SYNONYMS

别名信息,比如引用的对象和数据库链接db_link

SYS_PRIVS

系统权限,比如granteeprivilegeadmin选项

TAB_COLUMNS

表和视图的列信息,包括列的数据类型

TAB_PRIVS

表权限,比如授予者、被授予者和权限

TABLES

表信息,比如表空间(tablespace),存储参数(storage parms)和数据行的数量

TRIGGERS

触发器信息,比如类型、事件、触发体(trigger body)

USERS

用户信息,比如临时的和缺省的表空间

VIEWS

视图信息,包括视图定义


  在Oracle中还有一些不常用的数据字典表,但这些表不是真正的字典家族,他们都是一些重要的单一的视图。

VIEW NAME

描述

USER_COL_PRIVS_MADE

用户授予他人的列权限

USER_COL_PRIVS_RECD

用户获得的列权限

USER_TAB_PRIVS_MADE

用户授予他人的表权限

USER_TAB_PRIVS_RECD

用户获得的表权限


  其他的字典视图中主要的是V$视图,之所以这样叫是因为他们都是以V$GV$开头的。V$视图是基于X$虚拟视图的。V$视图是SYS用户所拥有的,在缺省状况下,只有SYS用户和拥有DBA系统权限的用户可以看到所有的视图,没有DBA权限的用户可以看到USER_ALL_视图,但不能看到DBA_视图。与DBA_,ALL,USER_视图中面向数据库信息相反,这些视图可视的给出了面向实例的信息。

 在大型系统上化几周时间手工输入每一条语句

 手工输入带用户名变量的语句,然后再输入每一个用户名,这需要花好几个小时的时间写一条SQL语句,生成需要的ALTER USER语句,然后执行他,这只需要几分钟时间
  很明显我们将选择生成SQL的方法:

  例:

SELECT 'ALTER USER'||username||
'TEMPORARY TABLESPACE temp;'
FROM DBA_USERS
WHERE username<>'SYS'
AND temporary_tablespace<>'TEMP';


  这个查询的结果将被脱机处理到一个文件中,然后在执行:

ALTER USER SYSTEM TEMPORARY TABLESPACE temp;
ALTER USER OUTLN TEMPORARY TABLESPACE temp;
ALTER USER DBSNMP TEMPORARY TABLESPACE temp;
ALTER USER SCOTT TEMPORARY TABLESPACE temp;
ALTER USER DEMO TEMPORARY TABLESPACE temp;

Oracle数据操作和控制

SQL言共分四大:数据查询语DQL,数据操纵语DML 数据定义语DDL,数据控制DCL。其中用于定数据的构,比如 建、修改或者除数据DCL用于定数据限;在篇文章中我将详细讲种语言在Oracle中的使用方法。

  DML

  DMLSQL的一个子集,主要用于修改数据,下表列出了ORACLE支持的DML句。

用途

INSERT

向表中添加行

UPDATE

更新存在表中的数据

DELETE

除行

SELECT FOR UPDATE

禁止其他用户访问DML句正在理的行。

LOCK TABLE

禁止其他用在表中使用DML

  插入数据

  INSERT句常常用于向表中插入行,行中可以有特殊数据字段,或者可以用子查询从已存在的数据中建立新行。

  列目是可的,缺省的列的目是所有的列名,包括comlumn_id,comlumn_id可以在数据字典视图ALL_TAB_COLUMNS,USER_TAB_COLUMNS,或者DBA_TAB_COLUMNS中找到。

  插入行的数据的数量和数据型必和列的数量和数据型相匹配。不符合列定的数据型将插入值实式数据转换NULL字符串将一个NULL插入适当的列中。关键NULL常常用于表示将某列定义为NULL

  下面的两个例子是等价的。

INSERT INTO customers(cust_id,state,post_code)
VALUE('Ariel',NULL,'94501');


  或

INSERT INTO customers(cust_id,state,post_code)
VALUE('Ariel',,'94501');


  更新数据

  UPDATE命令用于修改表中的数据。

UPDATE order_rollup
SET(qty,price)=(SELECT SUM(qty),SUM(price) FROM order_lines WHERE customer_id='KOHL'
WHERE cust_id='KOHL'
AND order_period=TO_DATE('01-Oct-2000')


  除数据

  DELETE句用来从表中除一行或多行数据,命令包含两个句:

   1关键DELETE FROM后跟准从中除数据的表名。

   2WHERE后跟除条件

DELETE FROM po_lines
WHERE ship_to_state IN ('TX','NY','IL')
AND order_date<TRUNC(SYSTEM)-90< td>


  清空表

  如果你想除表中所有数据,清空表,可以考使用DDL言的TRUNCATE句。TRUNCATE就像没有WHERE子句的DELETE命令一TRUNCATE除表中所有行。TRUNCATE不是DML句是DDL句,他和DELETE右不同的特点。

TRUNCATE TABLE (schema)table DROP(REUSE) STORAGE


  STORAGE子串是可的,缺省是DROP STORAGE。当使用DROP STORAGE短表和表索引,将表收到最小范,并重新NEXT参数。REUSE STORAGE不会短表或者NEXT参数。

  TRUNCATEDELETE有以下几点区

  1TRUNCATE在各表上无是大的是小的都非常快。如果有ROLLBACK命令DELETE将被撤,而TRUNCATE不会被撤

  2TRUNCATE是一个DDL言,向其他所有的DDL言一,他将被式提交,不能TRUNCATE使用ROLLBACK命令。

  3TRUNCATE将重新置高水平线和所有的索引。在整个表和索引行完全浏览时经过TRUNCATE操作后的表比DELETE操作后的表要快得多。

  4TRUNCATE不能触任何DELETE器。

  5、不能授予任何人清空他人的表的限。

  6、当表被清空后表和表的索引重新置成初始大小,而delete不能。

  7、不能清空父表。

  SELECT FOR UPDATE

  select for update句用于定行,阻止其他用行上修改数据。当行被定后其他用可以用SELECT查询该行的数据,但不能修改或行。

  定表

  LOCK句常常用于定整个表。当表被定后,大多数DML言不能在表上使用。LOCK法如下:

LOCK schema table IN lock_mode


  其中lock_mode有两个选项

   share 共享方式

   exclusive 唯一方式

  例:

LOCK TABLE intentory IN EXCLUSIVE MODE


  

  当两个事都被定,并且互相都在等待另一个被解这种情况称

  当出锁时ORACLE检测条件,并返回一个异常。

控制

  事控制包括协调对相同数据的多个同访问。当一个用了另一个用正在使用的数据oracle使用事控制可以操作数据。

  

  事表示工作的一个基本元,是一系列作一个元被成功或不成功操作的SQL句。在SQLPL/SQL中有很多程序控制事。程序可以:

   1始一个事物,选择语一致性或事务级一致性

   2置撤点,并回到回
 
   3、完成事数据或者放弃修改。
  
  控制

用途

Commit

完成事,数据修改成功并其他用户开

Rollback

,撤所有操作

rollback to savepoint

置的回点以后的操作

set transaction

句的一致性;特别对于事使用回


  例:

BEGIN
UPDATE checking
SET balance=balance-5000
WHERE account='Kieesha';

INSERT INTO checking_log(action_date,action,amount)
VALUES (SYSDATE,'Transfer to brokerage',-5000);

UPDATE brokerage
SET cash_balance=cash_balance+5000
WHERE account='Kiesha';

INSERT INTO brokerage_log(action_date,action,amount)
VALUES (SYSDATE,'Tracfer from checking',5000)

COMMIT

EXCEPTION
WHEN OTHERS
ROLLBACK

END


  Savepoint 部分回(Partial Rollback)

  在SQLPL/SQLSavepoint是在一事内的中间标志。常用于将一个的事划分小的部分。保留点Savepoint中的任何点,允可回滚该点之后的操作。用程序中常使用Savepoint;例如一程包含几个函数,在个函数前可建立一个保留点,如果函数失,很容易返回到一个函数始的情况。在回到一个Savepoint之后,Savepoint之后所得的数据封放。实现部分回可以用TO Savepoint子句的ROLLBACK句将事到指定的位置。

  例

BEGIN

INSERT INTO ATM_LOG(who,when,what,where)
VALUES ('Kiesha',SYSDATE,'Withdrawal of $100','ATM54')
SAVEPOINT ATM_LOGGED;

UPDATE checking
SET balance=balance-100
RETURN balance INTO new_balance;

IF new_balance<0
THEN
ROLLBACK TO ATM_LOGGED;
COMMIT
RAISE insufficient_funda;
END IF

END


  关键SAVEPOINT是可的,所以下面两个句是等价的:

ROLLBACK TO ATM_LOGGED;
ROLLBACK TO SAVEPOINT ATM_LOGGED;


  一致性和事

  一致性是事物控制的关键慨念。掌握了oracle 的一致性模型,能使您更好的,更恰当的使用事控制。oracle一致性保数据只有在事全部完成后才能被用和使用。这项术对多用数据有巨大的作用。

  oracle常常使用state-level)一致性,保数据在句的生命期之是可的但不能被改。事由多个成,当使用事务时,事物transaction-level)一致性在整个事生命期中保数据所有句都是可的。

  oracleSCN(syatem change number)施一致性。一个SCN是一个面向时间的数据内部SCN只会增加不会减少,SCN表示了时间上的一个点,个数据都有一个SCN,较这个点施操作。

  务级一致性

  SET TRANSACTION 的一个作用是确保事务级一致或一致中有一个施。ORACLE使用术语

   ISOLATION LEVEL READ COMMIT 表示一致

   ISOLATION LEVEL SERIALIZABLE 表示事务级一致。

  例:

SET TRANSACTION ISOLATION LEVEL READ COMMIT;

SET TRANSACTION ISOLATION LEVEL READ COMMIT


  下面的句也能确保事务级一致:

SET TRANSCATION READ ONLY


  任何企在只READ ONLY)事中修改数据的操作都会抛出一个异常。但是,READ ONLY只能在下列句中使用:

SELECT(没有FOR UPDATE子句)
LOCK TABLE
SET ROLE
ALTER SYSTEM
ALTER ALARM


  即使没有改任何数据,READ ONLY依然必使用一个COMMITROLLBACK束整个事

  SET TRANSCTION的另外一个用是在回滚时直接使用回段(ROLLBACK SEGMENT)。回段是ORACLE的一个特殊的数据象,回段的部包含正在使用段事的信息。当用ROLLBACKORACLE将会利用回段中的数据前影像来将修改的数据恢到原来的oracleround-robin随机分配回段。一个大的事可以分配任何回段,致回段的大小得很大。因此要避免大的事随机分配回段。

  事SET TRANSACTION,象下面这样

SET TRANSACTION USE ROLLBACK SEGMENT rb_large;


  rb_large是一个大的回段的名称,在就一个大的事分配了一个大的回段,其他的小的回段将不由动态管理,这样就更有效率。

  下面我看一个例子.有一个回段表空大小是2G,在高峰期需要10个回段以足用的需要,些高峰在线只有小的事。一周我们连续运行了4个大的事些事需要除和加数据,一个撤需要1G,回段的大小如下:

rb_large(initial 100M minextenta 2)

rb1 (initial 1M next minextents 5)
rb2 (initial 1M next minextents 5)
rb3 (initial 1M next minextents 5)
rb4 (initial 1M next minextents 5)
rb5 (initial 1M next minextents 5)
rb6 (initial 1M next minextents 5)
rb7 (initial 1M next minextents 5)
rb8 (initial 1M next minextents 5)
rb9 (initial 1M next minextents 5)
rb10 (initial 1M next minextents 5)


  所有的都非常恰当的安排在2G的表空中,如果我缺省的round-robin分配回段,4个大事将有4个独立的回段,个回段的大小将是1G,如果这样2G表空就不,而数据管理就不得不在夜2点起来工作,个事都由以下面的始:

SET TRANSACTION USE ROLLBACK SEGMENT rb_large


   4个事重用相同的表空,保正4个回段的表空2G以内。数据管理可以睡到天亮。

建立和修改用

  CREATE USER 句将建立一个用。当一个用户连接到ORACLE数据库时,它必验证ORACLE验证有三种类型:

   Database

   external

   Global

  缺省是数据库验证,当用户连接到数据库时oracle检测是否是数据的合法用,并且要提供正确的password.external验证oracle将只检测是否是合法用password被网或系统验证了。global验证也是只检测是否是合法用passwordoraclesecurity server验证

  Database验证户账

  数据库验证账号是好的缺省型,也是最普通的型。建立一个号是piyush,口令是welcome号,只需行下面的命令:

CREATE USE piyush IDENTIFIED BY welcome


  piyush可以通下面的句将口令改变为saraswatt:

ALTER USER piyush IDENTIFIED BY saraswati;


  外部验证户账

  用户账入数据库时可以不提供口令,这种情况下代替数据库识别口令的是客端操作系。外部验证账号有也叫OPS$号,当他最初在oracle6始介绍时oracle号都有关键字前OPS$,也就是init.ora 参数os_authent_prefixOPS$--特征与oracle6保持一致。os_authent_prefix的字符串必预处用于Oracle外部识别账号的操作系统账号名。建操作系appl句是:

CREATE USER ops$appl IDENTIFIED EATERNALLY


  但在通常情况下,os_authent_prefix将被空,像下面这样

CREATE USER appl IDENTIFIED EATERNALLY


  这样效果是一,关键IDENTIFIED EXTERNALLYORACLE是一个外部识别账号。

  GLOBAL户账

  GLOBAL型的用户账号数据检测口令,而是由X.509检测口令。建一个GLOBAL型的用户账号的方法是:

CREATE USER scott IDENTIFIED GLOBALLY AS "CN=scott,OU=divisional,O=sybex,C=US"


  关键IDENTIFIED GLOBALLY AS表示建立的是一个GLOBAL型的用户账.

  建和更改用户账

  CREATE USER 用于建立用户账号和户账号的属性赋值ALTER USER用于更改用户账号和属性。但CREATE USER句必包括用名和口令。

  有部分属性能用CREATER USERALTER USER置,下面些的属性具体描述:

  分配缺省表空

  表空tablespace)是放置表、索引、等用户对象的。如果在create user句中没有包含表空,那缺省的是系表空

CREATE USER piyush IDENTIFIED BY saraswati
DEFAULTE TABLESPACE user_data;
ALTER USER manoj DEFAULTE TABLESPACE dev1_data;


  分配临时表空

  临时表空名思临时存放表、索引等用户对象的临时段。建立方法一

CREATE USER piyush IDENTIFIED BY saraswati
Temporary TABLESPACE user_data;
ALTER USER manoj Temporary TABLESPACE dev1_data;


  分配表空的使用定

  使用定限制用在表空中使用磁的数量。定可以按字、千字、兆字或者无限制来制定。

CREATE USER piyush IDENTIFIED BY saraswati
DEFAULT TABLESPACE user_data
QUOTA UNLIMITED ON user_data
QUOTA 20M ON tools;
ALTER USER manoj QUOTA 2500K ON tools;


  分配一个

  表可以限制用在会话时消耗的源。源包括:接数据时间,空闲时间次会逻辑读数据的数量等等,缺省的对资源无限制。

CREATE USER piyush IDENTIFIED BY saraswati
PROFILE TABLESPACE user_data;
ALTER USER manoj Temporary TABLESPACE dev1_data;


  指定角色

  个属性只能由ALTER USER置,试图CREATE USER置将回返回一个例外。

ALTER USER manoj DEFAULT ROLE ALL EXCEPT salary_adm;


  password定到期时间以便在用下次登录时更改

  当用password到期,在下一次登录时迫修改passwordoracle提示用户输入旧的password,然后入新的password这项功能常用于新用,当新用用缺省的password录时修改立即修改password.

ALTER USER manoj IDENTIFIED BY welcome;
ALTER USER manoj PASSWORD EXPIRE;


  号,是用不能登

ALTER USER ql AC
COUNT LOCK


  对账号解,以便用能登数据

ALTER USER ql ACCOUNT UNLOCK


  限和角色

  限允户访问属于其它用象或行程序,ORACLE提供三种权限:

   Object

   System 统级

   Role 角色

  限可以授予、特殊用public或角色,如果授予一个特殊用"Public"(用publicoracle的,个用享有个用享有的限),就意味作将该权限授予了数据的所有用

  管理限而言,角色是一个工具,限能被授予一个角色,角色也能被授予另一个角色或用。用可以通角色限,除了管理限外角色服没有其它目的。限可以被授予,也可以用同的方式撤

  建立和使用角色

  如前所,角色存在的目的就是了使限的管理松。建立角色使用CREATE ROLE句,他的法如下:

CREATE ROLE role_name IDENTIFIED BY password
CREATE ROLE role_name IDENTIFIED EXTERNALLY
CREATE ROLE role_name IDENTIFIED GLOBALLY


  缺省情况下建立的角色没有password或者其他的识别如果使用IDENTIFIED BY 子句建立,那角色不会自,必SET ROLE激活。

SET ROLE role_name IDENTIFIED BY password


  EXTERNALLYGLOBALLY型的角色由操作系ORACLE Service server验证。通常用需要限修改用程序中使用的表中的数据,但是只有在用程序运行而不是在使用ad hoc工具这种上下文敏感安全可以通PASSWORD的角色来实现当用用程序内部连结数据库时,代SET ROLE命令,通安全验证。所以用不需要知道角色的password,也不需要自己SET ROLE命令。

  

  限就是指在表、视图、序列、程、函数或包等象上行特殊作的利。有九不同型的限可以授予或角色。如下表:

ALTER

DELETE

EXECUTE

INDEX

INSERT

READ

REFERENCE

SELECT

UPDATE

Directory

no

no

no

no

no

yes

no

no

no

function

no

no

yes

no

no

no

no

no

no

procedure

no

no

yes

no

no

no

no

no

no

package

no

no

yes

no

no

no

no

no

no

DB Object

no

no

yes

no

no

no

no

no

no

Libary

no

no

yes

no

no

no

no

no

no

Operation

no

no

yes

no

no

no

no

no

no

Sequence

yes

no

no

no

no

no

no

no

no

Table

yes

yes

no

yes

yes

no

yes

yes

yes

Type

no

no

yes

no

no

no

no

no

no

View

no

yes

no

no

yes

no

no

yes

yes


  象由不止一个限,特殊ALL可以被授予或撤。如TABLEALL限就包括:

   SELECT,INSERT,UPDATEDELETE,INDEX,ALTER,REFERENCE

  如何看个表我ALTER

  ALTER

  允许执ALTER TABLELOCK TABLE操作,ALTER TABLE可以行如下操作:

    . 更改表名

    . 增加或除列

    . 列的数据型或大小

    . 将表转变为分区表

  在SEQUENCE上的ALTER限允许执ALTER Sequence句,重新sequence分配最小、增量和冲区大小。

  统权

  系统权限需要授予者有行系统级的能力,如接数据,更改用、建立表或建立用等等。你可以在数据字典视图SYSTEM_PRIVILEGE_MAP得完整的系统权限。限和系统权限都通GRANT句授予用或角色。需要注意的是在授予时语应该WITH GRANT OPTION子句,但在授予系统权时语句是WITH ADMIN OPTION,所以在你试图授予系统权,使用WITH GRANT OPTION告一个错误ONLY ADMIN OPTION can be specified。在考中要特注意法和错误信息。

  角色和角色

  角色限就是将属于用限授予一个角色。任何限都可以授予一个角色。授予系统权被授予者必使用WITH_ADMIN_OPTION子句,在会SET ROLE句授予或撤角色限。然而,角色限不能依靠存SQL中的限。如果函数、程序、包、触器或者方法使用另一个有的象,那就必直接给对象的有者授是因为权限不会在会

  授予和撤销权

   或者角色授予限使用GRANT ,GRANT句的法如下:

GRANT ROLE(或system privilege TO user(role,Public) WITH ADMIN OPTION(可


  限被授予 WITH GRANT OPTION

  限和数据字典

  数据字典是ORACLE数据库结构信息的地方,数据本身存放在其他地方,数据字典由表和视图组成。在考于数据字典最容易考的内容是:看那一类权限已被授予。比如DBA_TAB_PRIV包含了用授予另一用限和在授予是否WITH GRANT OTPION子串的信息。注意DBA_TAB_PRIV仅仅包含了表的限的系,他包括函数、包、列等等上的限的系。下表列出了所有的限和角色的数据字典视图

  表: 限的数据字典视图

视图

作用

ALL_COL_PRIVS

表示列上的授,用PUBLIC是被授予者

ALL_COL_PRIVS_MADE

表示列上的授,用是属主和被授予者

ALL_COL_RECD

表示列上的授,用PUBLIC是被授予者

ALL_TAB_PRIVS

表示象上的授,用PUBLIC或被授予者或用是属主

ALL_TAB_PRIVS_MADE

表示象上的限,用是属主或授予者

ALL_TAB_PRIVS_RECD

表示象上的, PUBLIC或被授予者

DBA_COL_PRIVS

数据列上的所有授

DBA_ROLE_PRIVS

示已授予用或其他角色的角色

DBA_SYS_PRIVS

已授予用或角色的系统权

DBA_TAB_PRIVS

数据库对象上的所有

ROLE_ROLE_PRIVS

示已授予用的角色

ROLE_SYS_PRIVS

示通角色授予用的系统权

ROLE_TAB_PRIVS

示通角色授予用

SESSION_PRIVS

示用户现在可利用的所有系统权

USER_COL_PRIVS

示列上的限,用是属主、授予者或被授予者

USER_COL_PRIVS_MADE

示列上已授予的限,用是属主或授予者

USER_COL_PRIVS_RECD

示列上已授予的限,用是属主或被授予者

USER_ROLE_PRIVS

示已授予的所有角色

USER_SYS_PRIVS

示已授予的所有系统权

USER_TAB_PRIVS

示已授予的所有

USER_TAB_PRIVS_MADE

示已授予其他用限,用是属主

USER_TAB_PRIVS_RECD

示已授予其他用限,用是被授予者

 

Oracle数据使用大全

 

SQL是用于访问ORACLE数据言,PL/SQL展和加SQL的功能,它同引入了更的程序逻辑 PL/SQL支持DML命令和SQL的事控制句。DDLPL/SQL中不被支持,就意味作在PL/SQL程序中不能建表或其他任何象。好的PL/SQL程序设计是在PL/SQL中使用象DBMS_SQL这样的内建包或EXECUTE IMMEDIATE命令建立动态SQLDDL命令,PL/SQL编译器保证对象引用以及用限。

  下面我讨论用于访问ORACLE数据DDLTCL句。

  查询

  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/SQLSELECT句只返回一行数据。如果超一行数据,那就要使用式游讨论将在后面行),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句是:INSERTUPDATEDELETELOCK 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句的果保存在四个游属性中,些属性用于控制程序流程或者了解程序的状。当运行DMLPL/SQL一个内建游果,游维护查询结果的内存中的一个区域,游在运行DML,完成后关闭式游只使用SQL%FOUND,SQL%NOTFOUND,SQL%ROWCOUNT三个属性.SQL%FOUND,SQL%NOTFOUND是布尔值SQL%ROWCOUNT是整数

  SQL%FOUNDSQL%NOTFOUND

  在行任何DML句前SQL%FOUNDSQL%NOTFOUND都是NULL,DML句后,SQL%FOUND的属性将是:

  . TRUE :INSERT

  . TRUE :DELETEUPDATE,至少有一行被DELETEUPDATE.

  . TRUE :SELECT INTO至少返回一行

  当SQL%FOUNDTRUE,SQL%NOTFOUNDFALSE

  SQL%ROWCOUNT

  在行任何DML句之前,SQL%ROWCOUNT都是NULL,SELECT INTO句,如果行成功,SQL%ROWCOUNT值为1,如果没有成功,SQL%ROWCOUNT值为0,同时产生一个异常NO_DATA_FOUND.

  SQL%ISOPEN

  SQL%ISOPEN是一个布尔值,如果游则为TRUE, 如果游标关闭则为FALSE.式游而言SQL%ISOPENFALSE是因为隐式游DML就立即关闭

  控制

  事是一个工作的逻辑单元可以包括一个或多个DML句,事物控制帮助用数据的一致性。如果事控制逻辑单元中的任何一个DML句失,那整个事都将回,在PL/SQL中用可以明确地使用COMMITROLLBACKSAVEPOINT以及SET TRANSACTION句。

  COMMIT止事,永久保存数据化,同时释放所有LOCK,ROLLBACK行事务释放所有LOCK,但不保存数据的任何,SAVEPOINT用于置中点,当事务调多的数据操作,中点是非常有用的,SET TRANSACTION用于置事属性,比如read-write和隔离等。

  式游

  当查询返回果超一行,就需要一个式游,此不能使用select into句。PL/SQL管理式游,当查询开时隐式游查询结时隐式游动关闭式游PL/SQL的声明部分声明,在行部分或异常理部分打,取数据,关闭。下表示了式游式游的差

                 表1 式游式游

式游

式游

PL/SQL维护,当查询时关闭

在程序中式定、打关闭,游有一个名字。

属性前SQL

属性的前是游

属性%ISOPENFALSE

%ISOPEN根据游的状确定

SELECTINTO子串,只有一行数据被

可以理多行数据,在程序中置循,取出一行数据。

使用游


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

  声明游

  法:

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中依然可以使用UPDATEDELETE句更新或除数据行。式游只有在需要得多行数据的情况下使用。PL/SQL提供了仅仅使用游就可以除或更新记录的方法。

  UPDATEDELETE句中的WHERE CURRENT OF子串专门处理要UPDATEDELETE操作的表中取出的最近的数据。要使用个方法,在声明游标时使用FOR UPDATE子串,当对话使用FOR UPDATE子串打一个游标时,所有返回集中的数据行都将于行ROW-LEVEL)独占式定,其他象只能查询这些数据行,不能UPDATEDELETESELECT...FOR UPDATE操作。

  法:

FOR UPDATE [OF [schema.]table.column[,[schema.]table.column]..
[nowait]


  在多表查询中,使用OF子句来定特定的表,如果忽略了OF子句,那所有表中选择的数据行都将被定。如果些数据行已被其他会话锁定,那正常情况下ORACLE将等待,直到数据行解

  UPDATEDELETE中使用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

PL/SQL异常理初

PL/SQL理异常不同于其他程序言的错误管理方法,PL/SQL的异常理机制与ADA很相似,有一个错误的全包含方法。当错误时,程序无条件到异常理部分,就要求代要非常干并把错误处理部分和程序的其它部分分oracle声明其他异常条件型以错误/异常理。这种扩展使PL/SQL的异常理非常灵活。

  当一个运行时错误发,称一个异常被抛出。PL/SQL程序编译时错误不是能被理得异常,只有在运行的异常能被理。在PL/SQL程序设计中异常的抛出和理是非常重要的内容。

  抛出异常

  由三方式抛出异常

   . PL/SQL运行引擎

   . 使用RAISE

   . RAISE_APPLICATION_ERROR储过

  当数据PL/SQL在运行时发错误时,一个异常被PL/SQL运行引擎自抛出。异常也可以通RAISE句抛出

  RAISE exception_name;

  式抛出异常是程序员处理声明的异常的习惯用法,但RAISE不限于声明了的异常,它可以抛出任何任何异常。例如,你希望用TIMEOUT_ON_RESOURCE错误检测新的运行异常理器,你只需简单的在程序中使用下面的句:

  RAISE TIMEOUT_ON_RESOUCE;

  下面看一个订单输入系,当存小于订单时抛出一个inventory_too_low异常。

DECLARE
inventory_too_low EXCEPTION;
---
其他声明
BEGIN
.
.
IF order_rec.qty>inventory_rec.qty THEN
RAISE inventory_too_low;
END IF
.
.
EXCEPTION
WHEN inventory_too_low THEN
order_rec.staus:='backordered';
replenish_inventory(inventory_nbr=>
inventory_rec.sku,min_amount=>order_rec.qty-inventory_rec.qty);
END;


  replenish_inventory是一个触器。
 
  理异常

  PL/SQL程序的异常部分包含了程序错误的代,当异常被抛出,一个异常陷阱就自动发生,程序控制离开执行部分入异常部分,一旦程序入异常部分就不能再回到同一行部分。下面是异常部分的一般法:

EXCEPTION
 WHEN exception_name THEN
  Code for handing exception_name
 [WHEN another_exception THEN
  Code for handing another_exception]
 [WHEN others THEN
  code for handing any other exception.]


  用在独立的WHEN子串中为每个异常设计异常理代WHEN OTHERS子串必放置在最后面作缺省理器理没有理的异常。当异常,控制到异常部分,ORACLE找当前异常相WHEN..THEN句,捕捉异常,THEN之后的代行,如果错误陷阱代只是退出相的嵌套,那程序将继续执行内部END后面的句。如果没有找到相的异常陷阱,那WHEN OTHERS。在异常部分WHEN 子串没有数量限制。

EXCEPTION

 WHEN inventory_too_low THEN
  order_rec.staus:='backordered';
  replenish_inventory(inventory_nbr=>
  inventory_rec.sku,min_amount=>order_rec.qty-inventory_rec.qty);
 WHEN discontinued_item THEN
  --code for discontinued_item processing
 WHEN zero_divide THEN
  --code for zero_divide
 WHEN OTHERS THEN
  --code for any other exception
END;


  当异常抛出后,控制无条件到异常部分,就意味着控制不能回到异常生的位置,当异常被理和解决后,控制返回到上一层执行部分的下一条句。

BEGIN
 DECLARE
  bad_credit;
 BEGIN
  RAISE bad_credit;
   --生异常,控制向;
 EXCEPTION
  WHEN bad_credit THEN
   dbms_output.put_line('bad_credit');
  END;

  --bad_credit异常理后,控制
 EXCEPTION
  WHEN OTHERS THEN
   --控制不会从bad_credit异常
   --bad_credit已被
END;



  当异常,在的内部没有异常理器,控制将到或播到上一层块的异常理部分。

BEGIN
 DECLARE ---内部块开
  bad_credit;
 BEGIN
  RAISE bad_credit;
   --生异常,控制向;
  EXCEPTION
  WHEN ZERO_DIVIDE THEN --不能bad_credite异常
   dbms_output.put_line('divide by zero error');
  END --束内部

   --控制不能到达里,因异常没有解决;
   --异常部分

  EXCEPTION
  WHEN OTHERS THEN
   --由于bad_credit没有解决,控制将
END;


  异常

  没有理的异常将沿检测异常用程序播到外面,当异常被理并解决或到达程序最外层传播停止。
在声明部分抛出的异常将控制到上一的异常部分。

BEGIN
executable statements
BEGIN
today DATE:='SYADATE'; --ERRROR
BEGIN --
内部块开
dbms_output.put_line('this line will not execute');
EXCEPTION
WHEN OTHERS THEN
--
异常不会在
END;--
内部块结

EXCEPTION
WHEN OTHERS THEN
理异常
END


  行部分抛出的异常将首先传递到同一的异常部分,如果在同一的异常部分没有个异常的理器,那异常将会播到上一的异常部分中,一直到最外

  在异常部分抛出的异常将控制到上一的异常部分。

  理异常将停止异常的播和解决。有希望在错误发,程序仍然能行一些作,要达到个目的,可以把希望行的作放在异常理器中,然后行不参数的RAISE句,RAISE句将重新抛出出的异常,允继续传播。

DECLARE
order_too_old EXCEPTION;
BEGIN
RAISE order_too_old;
EXCEPTION
WHEN order_too_old THEN
DECLARE
file_handle UTL_FILE.FILE_TYPE;
BEGIN
--open file
file_handle:=UTL_FILE.FOPEN
(location=>'/ora01/app/oracle/admin/test/utlsir'
,filename=>'error.log'
.open_mode=>'W');
--write error stack
UTL_FILE.PUT_LINE(filehandle,
DBMS_UTILITY.FORMAT_ERROR_STACK);
--write the call stack
UTL_FILE.PUT_LINE(filehandle,
DBMS_UTILITY.FORMAT_CALL_STACK);
--close error log
UTL_FILE.FCLOSE(file_handle);
RAISE; --re-raise the exception
END
END


  如果从FORMAT_XXX_STACK出一个很大的,那使用DBMS_OUTPUTUTL_FILE错误用堆的异常部分自身也会抛出异常,两个堆常下最多能返回2000,但utl_file.put_line被限制在1000以内,而dbms_output.put_line限制在512内。如果使用前面的代并且不允许这种可能性,那在异常理器中将抛出一个未理的异常。

  GOTO句不能用于将控制从行部分传递到异常部分或反之。

  已命名异常

  在PL/SQL的异常部分只有已命名的异常才能被WHEN子串理,ORACLE包含了一系列已命名的异常,些异常都声明在STANDARD包中,些内建异常在里就不一一述,有趣的者可以查阅关资料。

常用异常理方法

  除了准异常外,用可以声明自己的已命名异常。比如商业规则错误,或者将自定异常与一个数据号相系,甚至可以将数据库错误予自定异常。PL/SQL个性能极大的提高了异常的管理和理的能力。

  声明自己的异常 

  如果你希望声明自己的异常,那你可以在异常理器中包括WHEN子句,声明的异常的作用范与声明的量相同。声明在外层块的异常能被该块和它的子块访问,但声明在子的异常不能被父块处理。
 
  例:

 BEGIN
DECLARE
Insufficient_credite EXCEPTION;
BEGIN
RASISE Insufficient_credite;
EXCEPTION
WHEN Insufficient_credite THEN
--
可以在此理异常
   extend_credite(cust_id);
END
 -嵌套块结
EXCEPTION
WHEN Insufficient_credite THEN
--
超出范,不能在理异常
 END;


  如果声明的异常与内建的异常同名,那当引用异常将解决你的异常而不是内建的异常。

  数据库错误命名

  如果希望理一个异常,那异常必有一个名字,数据库错误有数千个,但是只有不到25个是内建的已命名异常,但需要些未命名的异常,你可以将一个名字和一个错误系在一起,达到个目的的句是:PRAGMA EXCEPTION_INIT

  法如下:

  PRAGMA EXCEPTION_INIT(exception_nameerror_number);

  句之前,必首先声明异常名。

DECLARE
invald_table_name EXCEPTION;
PRAGMA EXCEPTION_INIT(invald_table_name,-942);
BEGIN

EXCEPTION
WHEN invald_table_name THEN
UTL_FILE.PUT_LINE(file_handle,'user' || UID || 'hit a bad table');
END;


  另外一种处理数据库错误的方法是使用内建函数SQLCODESQLERRM两个函数在包一声明,SQLCODE将返回行数据库错误号,错误号中除了NO_DATA_FOUND+100外其他都是数。SQLERRM返回文本描述的错误信息。得用自定异常返回的SQLERRMSQLCODE,你需要使用RAISE_APPLICATION_ERROR函数自定异常错误号。

  自定义错误标注号

  RAISE_APPLICATION_ERROR内建函数用于抛出一个异常并异常予一个错误号以及错误信息。自定异常的缺省错误号是+1,缺省信息是User_Defined_Exception。来自未理的异常的一般信息识别导错误的原因没有帮助,RAISE_APPLICATION_ERROR函数能pl/sql程序行部分和异常部分用,式抛出特殊错误号的命名异常。

RAISE_APPLICATION_ERROR(error_name,error_message[,{TRUE|| FALSE}]);


  错误号的范-20,999-20,999错误信息是文本字符串,最多2048TRUEFALSE表示是添加(TRUE)进错误(ERROR STACK)是覆盖(overwrite)错误(FALSE)。缺省情况下是FALSE

IF product_not_found THEN
  RAISE_APPLICATION_ERROR(-20123,'Invald product code' TRUE);
END IF;