PLSQL

更新时间:2024-02-02 14:01:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

PL/SQL是ORACLE对标准数据库语言的扩展,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能够运行的操作系统都是非常便利的

. 对于SQL,ORACLE必须在同一时间处理每一条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块由BEGIN或DECLARE开始,以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 要求存储长度低于NUMBER值。 NPOSITIVE 用于限制范围的子类型(SUBTYPE): POSITIVEN NATURAL:用于非负数 SIGNTYPE POSITIVE:只用于正数 NATURALN:只用于非负数和非NULL值 POSITIVEN:只用于正数,不能用于NULL值 SIGNTYPE:只有值:-1、0或1. NUMBER 1.0E-130-9.99E125 DEC DECIMAL 存储数字值,包括整数和浮点数。可以选择精度和刻度方式,语法: DOUBLE number[([,])]。 PRECISION 缺省的精度是38,scale是0. FLOAT INTEGERIC INT NUMERIC REAL SMALLINT PLS_INTEGER -2147483647-2147483647 与BINARY_INTEGER基本相同,但采用机器运算时,PLS_INTEGER提供更好的性能 。

表2 字符数据类型

datatype CHAR rang 最大长度32767字节 最大长度2147483647字节 最大长度32767字节 最大长度2147483647 18个字节 最大长度32767字节 subtype CHARACTER description 存储定长字符串,如果长度没有确定,缺省是1 LONG 存储可变长度字符串 用于存储二进制数据和字节字符串,当在两个数据库之间进行传递时,RAW数据不在字符集之间进行转换。 与LONG数据类型相似,同样他也不能在字符集之间进行转换。 与数据库ROWID伪列类型相同,能够存储一个行标示符,可以将行标示符看作数据库中每一行的唯一键值。 与VARCHAR数据类型相似,存储可变长度的字符串。声明方法与VARCHAR相同 RAW LONGRAW ROWID VARCHAR2 STRINGVARCHAR

表3 DATE和BOOLEAN

datatype range description

BOOLEAN DATE TRUE/FALSE 01/01/4712 BC 存储逻辑值TRUE或FALSE,无参数 存储固定长的日期和时间值,日期值中包含时间

LOB数据类型

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

. BFILE . BLOB . CLOB . NCLOB

操作符

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

. 算术操作符

. 关系操作符

. 比较操作符

. 逻辑操作符

算术操作符如表4所示

operator + - / * ** operation 加 减 除 乘 乘方

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

operator < operation 小于操作符 <= > >= = != <> := 小于或等于操作符 大于操作符 大于或等于操作符 等于操作符 不等于操作符 不等于操作符 赋值操作符

表6 显示的是比较操作符

operator IS NULL LIKE BETWEEN IN operation 如果操作数为NULL返回TRUE 比较字符串值 验证值是否在范围之内 验证操作数在设定的一系列值中

表7.8显示的是逻辑操作符

operator AND OR NOT operation 两个条件都必须满足 只要满足两个条件中的一个 取反

执行部分

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

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

执行一个PL/SQL块

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

declare v_comm_percent constant number:=10; begin update emp set comm=sal*v_comm_percent where deptno=10; end SQL> / PL/SQL procedure successfully completed. SQL>

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

create or replace procedure update_commission (v_dept in number,v_pervent in number default 10) is begin update emp

set comm=sal*v_percent where deptno=v_dept; end SQL>/

Procedure created

SQL>execute update_commission(10,15);

PL/SQL procedure successfully completed. SQL>

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

declare v_dept number; begin select a.deptno into v_dept from emp a where job='PRESIDENT' update_commission(v_dept); end SQL>/ PL/SQL procedure successfully completed SQL> 控制结构

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

语法和用途

IF..THEN

语法:

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

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

IF..THEN...ELSE

语法:

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

如果条件condition为TRUE,则执行THEN到ELSE之间的语句,否则执行ELSE到END IF之间的语句。

IF 可以嵌套,可以在IF 或IF ..ELSE语句中使用IF或IF..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;

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

循环控制

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

LOOP statements; END LOOP

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

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

此时Y的值是1010.

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

引用记录

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

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 INTO或FETCH给整个记录或单独的域赋值, 可以将整个记录的值赋给其他记录,也可以通过给每个域赋值来得到记录,以下我们通过实例讲解每一种赋值方法。

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 . 可以使用数据库对象,数据库对象可以使用order或map方法定义,允许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/INTEGER、SIGNTYPE、和BOOLEAN。其他的集合类型对数据库的数据类型都有限制,但Index_by表不能存储在数据库中,所以没有这些限制。

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

DECLARE TYPE symbol_tab_typ IS TABLE OF VARCHAR2(5) INDEX 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,BOOLEAN或SIGNTYPE)。

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

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

VARRAY

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

TYPE type_name IS [VARRAY|VARYING ARRAY] (max_size) OF element_type [NOT NULL] max_size是一个整数,用于标示VARRAY集合拥有的最多元素数目。VARRAY集合的元素数量可以低于max_size,但不能超过max_size。element_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(5) INDEX 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):=\ symbol_tab(2):=\ symbol_tab(3):=\

publish_portfolio(symbol_tab);

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

例:

DECLARE TYPE stock_list IS TABLE OF stock.symbol%TYPE; TYPE top10_list IS VARRAY (10) OF 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 删除集合中所有元素 对VARRAY非法 对VARRAY非法 对Index_by非法 对Index_by非法 对Index_by非法 DELETE() 删除元素下标为x的元素,如果x为null,则集合保持不变 DELETE(,) 删除元素下标从X到Y的元素,如果X>Y集合保持不变 EXIST() EXTEND 如果集合元素x已经初始化,则返回TRUE, 否则返回FALSE 在集合末尾添加一个元素 EXTEND() 在集合末尾添加x个元素 EXTEND(,) 在集合末尾添加元素 n的x个副本 FIRST LAST LIMIT NEXT() 返回集合中的第一个元素的下标号,对于VARRAY集合始终返回1。 返回集合中最后一个元素的下标号, 对于VARRAY返回值始终等于COUNT. 返回VARRY集合的最大的元素个数,对于嵌套表和对于嵌套表和Index_by为null Index_by 集合无用 返回在元素x之后及紧挨着它的元素的值,如果该元素是最后一个元素,则返回null. 返回集合中在元素x之前紧挨着它的元素的值,如果该元素是第一个元素,则返回null。 从集合末端开始删除一个元素 从集合末端开始删除x个元素 PRIOR() 对于index_by不合法 对index_by不合法 TRI M TRIM() 关于集合之间的比较

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

IF stock_list1>stock_list2 ----非法 IF sort_collection(stock_list1)>sort_collection(stock_list2) THEN --合法 但可以比较在集合内的两个元素。

PL/SQL单行函数和组函数详解

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

单行函数

组函数

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

SQL中的单行函数

SQL和PL/SQL中自带很多类型的函数,有字符、数字、日期、转换、和混合型等多种函数用

于处理单行数据,因此这些都可被统称为单行函数。这些函数均可用于SELECT,WHERE、ORDER 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)

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

NULL和单行函数

在如何理解NULL上开始是很困难的,就算是一个很有经验的人依然对此感到困惑。NULL值表示一个未知数据或者一个空值,算术操作符的任何一个操作数为NULL值,结果均为提个NULL值,这个规则也适合很多函数,只有CONCAT,DECODE,DUMP,NVL,REPLACE在调用了NULL参数时能够返回非NULL值。在这些中NVL函数时最重要的,因为他能直接处理NULL值,NVL有两个参数:NVL(x1,x2),x1和x2都式表达式,当x1为null时返回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的后面,如果c1为null,将返回c2.如果c2为null,则返回c1,如果c1、c2都为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为整数。函数返回c2在c1中第j次出现的位置,搜索从c1的第i个字符

开始。当没有发现需要的字符时返回0,如果i为负数,那么搜索将从右到左进行,但是位置的计算还是从左到右,i和j的缺省值为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的长度,如果c1为null,那么将返回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()

反余玄函数,返回-1到1之间的数。n表示弧度

select ACOS(-1) pi,ACOS(1) ZERO FROM dual PI ZERO 3.14159265 0

ASIN()

反正玄函数,返回-1到1,n表示弧度

ATAN()

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

CEIL()

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

COS()

返回n的余玄值,n为弧度

COSH()

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

select COSH(<1.4>) FROM dual COSH(1.4) 2.15089847

EXP()

返回e的n次幂,e=2.71828183.

FLOOR()

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

LN()

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

LOG(,)

返回以n1为底n2的对数

MOD()

返回n1除以n2的余数,

POWER(,) 返回n1的n2次方

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(,)

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

NEW_TIME(,,)

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

NEXT_DAY(,)

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

select NEXT_DAY('01-Jan-2000','Monday') \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尾字符串,dset、sset是两个字符集,函数将字符串c由sset字符集转换为dset字符集,sset的缺省设置为数据库的字符集。

HEXTORAW()

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

RAWTOHEX()

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

ROWIDTOCHAR()

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

TO_CHAR([[,)

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

NLS_NUMERIC_CHARACTERS =\

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是一个匹配表达式,x与m1比较,如果m1等于x,那么返回r1,否则,x与m2比较,依次类推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提供了丰富的基于组的,多行的函数。这些函数可以在select或select的having子句中使用,当用于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数据类型,返回一个日期,如果X是numeric数据类型,返回一个数字。注意distinct和all不起作用,应为最大值与这两种设置是相同的。

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_ID,EMPLOYEE_NAME,SALARY) 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数据库数据对象分析(中)

完整性约束

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

Check NOT NULL Unique Primary Foreign key

完整性约束是一种规则,不占用任何数据库空间。完整性约束存在数据字典中,在执行SQL或PL/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,至少一个数据列的值是NULL,Check约束用于增强表中数据内容的简单的商业规则。用户使用Check约束保证数据规则的一致性。Check约束可以涉及该行同属Check约束的其他数据列但不能涉及其他行或其他表,或调用函数SYSDATE,UID,USER,USERENV。如果用户的商业规则需要这类的数据检查,那么可以使用触发器。Check约束不保护LOB数据类型的数据列和对象、嵌套表、VARRY、ref等。单一数据列可以有多个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 NULL的ALTER 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中,主键作用于数据列MAKE,MODEL,YEAR上,用户使用的表INSURED_AUTOS有一个外部约束指向AOTOMOBILES,注意在INSURES_AUTOS中有一数据行的MODEL列为NULL值,这一行数据已经通过约束检查,即使MAKE列也没有显示在父表AUTOMOBILES中,如下表:

表1 AUTOMOBILES

MAKE Ford Toyota MODEL Taurus Camry YEAR 2000 1999

表2 INSURED_AUTOS

POLICY_ID 576 577 578 MAKE Ford Toyota Tucker MODEL Taurus Camry NULL YEAR 2000 1999 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 MINVALUE 定义序列号是上升还是下降,对于一个降序的序列INCREMENT BY为负值 定义序列可以生成的最小值,这是降序序列中的限制值。缺省情况下该值为NOMINVALUE,NOMINVALUE,对于升序为1,对于降序为-10E26. 序列能生成的最大数字。这是升序序列中的限制值,缺省的MAXVALUE为NOMAXVALUE,NOMAXVALUE,对于升序为10E26,对于降序为-1。 设置序列值在达到限制值以后可以重复 设置序列值在达到限制值以后不能重复,这是缺省设置。当试图产生MAXVALUE+1的值时,将会产生一个异常 定义序列值占据的内存块的大小,缺省值为20 在每次序列号产生时强制数据字典更新,保证在序列值之间没有间隔当创建序列时,START WITH值必须等于或大于MINVALUE。 MAXVALUE CYCLE NOCYCLE CACHE NOCACHE

删除序列使用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)列,在这些列上多位图索引可以与AND或OR操作符结合使用。位图索引使用位图作为键值,对于表中的每一数据行位图包含了TRUE(1)、FALSE(0)、或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; Oracle数据库数据对象分析(下)

过程和函数

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

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有三种形式:IN、OUT、INOUT。

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

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

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

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

CREATE [ OR REPLACE] FINCTION [schema.]function_name [parameter_list]

本文来源:https://www.bwwdw.com/article/i62w.html

Top