Oracle数据库的简单应用
本文内容包括:
1,数据类型
2,自增长ID
3,SQL语句
4,存储过程:基本语法,游标,异常处理
对Oracle数据库的使用,我是个初学者。如果不是项目的需要,我可能连做初学者的机会也没有了。在小心翼翼、如履薄冰般地完成了数据库端的一些开发工作之后,我认为有必要把一些重要的和犯过错误的地方记录下来,给自己和大家参考。当然,我并不想做大而全的总结,也远没有达到这样的水平。
数据类型
Oracle的数据类型和SQL Server有一些出入,这一点至少在数据类型的名称上就看得出来。常用的类型就是字符,数字,日期这些了。
SQL Server 常用的字符类型有char,nchar,varchar,nvarchar,对于超长的字符,还有text,ntext等。 常用的数字类型有int,bigint,smallint,tinyint,decimal,float,real等。 日期是datetime和smalldatetime,还有一个时间戳类型timestamp,用法较特殊。其他的还有binary,bit,cursor,image,money,smallmoney,varbinary,uniqueidentifier等。其中uniqueidentifier对应了.Net中的GUID类型。
Oracle(9i)(注:这段摘自网络)
基本数据类型有:
char 用于描述定长的字符型数据,长度<=2000字节
varchar2 用于描述变长的字符型数据,长度<=4000字节
nchar 用来存储Unicode字符集的定长字符型数据,长度<=1000字节
nvarchar2 用来存储Unicode字符集的变长字符型数据,长度<=1000字节
number 用来存储整型或者浮点型数值
date 用来存储日期数据
long 用来存储最大长度为2GB的变长字符数据
raw 用来存储非结构化数据的变长字符数据,长度<=2000字节
long raw 用来存储非结构化数据的变长字符数据,长度<=2GB
rowid 用来存储表中列的物理地址的二进制数据,占用固定的10个字节
Blob 用来存储多达4GB的非结构化的二进制数据
clob 用来存储多达4GB的字符数据
nclob 用来存储多达4GB的Unicode字符数据
bfile 用来把非结构化的二进制数据存储在数据库以外的操作系统文件中
urowid 用来存储表示任何类型列地址的二进制数据
float 用来存储浮点数
自增长ID
了解了以上数据类型之后,就可以建立自己的数据表了。慢~慢~慢~,我要建立一个类似SQL Server中的自增长列,Oracle中怎么没有IDENTITY的属性设置呢?
其实在Oracle中,有类似的实现,只是稍微麻烦点,这个东西就是sequence。它定义了一个自增长的对象,每次查询了它的值以后,它会自增长1(1个step)。可以看看如下的创建sequence的sql语句
create sequence SEQ_BLOG_ID
minvalue 1
maxvalue 999999999999999999999999999
start with 1
increment by 1
cache 20;
要使用SEQ_BLOG_ID时,可以先定义一个变量V_SEQ_BLOG_ID NUMBER(10); 然后用执行SELECT SEQ_BLOG_ID.NEXTVAL INTO V_SEQ_BLOG_ID FROM DUAL;就可以的到SEQ_BLOG_ID的当前值了。很明显,这个当前值存入了变量V_SEQ_BLOG_ID中,当然,你也可以不定义变量而直接使用sql语句查看sequence的当前值。
SQL语句
Oracle和SQL Server当然都支持标准的SQL语句,但是我们常常需要使用一些“个性化”的SQL语句,以达到简洁、高效的效果。我就遇到了一些这样的情况,下面举个例子:
在SQL Server中,对于这样的情景,我们可能会使用update xxx from xxx语句:两个表,Student表存储了学生的信息,其中有ID,Name,Score等字段;StudentScore(成绩表),包括StudentID,EnglishScore,MathScore…等字段。要求把StudentScore中学生的总成绩根据更新到Student表的Score中。
一种方法是写一个循环,遍历每个学生,然后将他们的各门功课成绩相加,让后根据StudentScore.StudentID=Student.ID更新到Student.Score。
这样做显然比较麻烦,可以考虑使用update Student set Student.Score=StudentScore.EnglishScore +StudentScore.MathScore +… from StudentScore where StudentScore.StudentID=Student.ID;一句话就解决了战斗。
同样的,要找Oracle中实现上述的功能,用一句sql解决问题,就要这样来了:update Student set Student.Score=(select StudentScore.EnglishScore +StudentScore.MathScore +… from StudentScore where StudentScore.StudentID=Student.ID) where exists(select 1 from StudentScore where StudentScore.StudentID=Student.ID);
简单解释一下,这个sql语句的主干是: update Student set Student.Score=成绩合计 where 存在学号相等的学生。 可以这样理解:如果存在学号相等的学生,那么就把成绩的合计值更新到对应的Student的Score字段。这里的对应的是怎么实现的呢?就是从句(select StudentScore.EnglishScore +StudentScore.MathScore +… from StudentScore where StudentScore.StudentID=Student.ID)中的where后的部分StudentScore.StudentID=Student.ID。
值得一提的是,Oracle允许一次update多列的值,如update (column1,column2,…) =(select col1,col2,…) from xxx where xxx,但要求等号两端列的个数和对应数据类型相同。另外如果作为值的记录数大于被更新的记录数,会报异常。
这里还有个语句是关于select into 的。我们知道这个语句是从表里选出某些字段的值,放入into后面的变量里。在SQL Server中,如果要选出10个字段的值,我们就得定义10个变量。Oracle提供了一种好用的类型——行类型。
定义行类型
declare curStudentScore_Row StudentScore%rowtype;
使用行类型
select * into curStudentScore_Row from StudentScore where StudentID =1;
totalScore :=curStudentScore_Row.EnglishScore + curStudentScore_Row.MathScore +…;
怎么样,很方便吧!
存储过程
在Oracle中,准确的说法应该是“过程”(Procedure)。编写过程常见的问题是
- 过程结构,命名,参数。这个查看一下已有的过程就一目了然了。注意begin 和end成对出现。
- 变量定义和赋值。就像在前面“自增长ID”一段中所述的那样V_SEQ_BLOG_ID NUMBER(10); 就是定义了一个名称为V_SEQ_BLOG_ID,类型为NUMBER(10)的变量。注意别忘了分号(;)。赋值使用V_SEQ_BLOG_ID :=100;的形式,冒号等号(:=)。
- 条件语句
if xxx then
begin
xxx
end;
end if;
- 循环
while xxx loop
begin
xxx
end;
end loop;
或者
for xxx in xxx loop
begin
xxx
end;
end loop;
- 游标
定义游标
declare cursor curStudentScore is select * from StudentScore a;
使用游标的方式有几种,一种是使用SQL Server中的Fetch;这里介绍一个最简单的,使用for语句(这里curStudentScore_Row不需要预先定义)
for curStudentScore_Row in curStudentScore loop
begin
//在这里可以直接通过curStudentScore_Row.EnglishScore的形式访问StudentScore中的字段EnglishScore的值。
end;
end loop;
使用完后,游标也不需要显式地关闭。真是方便啊!
- 异常
在SQL Server(2005)中,捕获异常是通过try… catch…来实现的,可以参考前面我的一篇文章SQL Server 2005存储过程开发的一点经验。在Oracle中,定义异常处理的语句是形如下面的语句
exception
when no_data_found then xxx;when others then return;
说明一下,当过程中的某个语句发生异常时,会进入其后的最近一个exception,并根据when后的条件,进入相应的处理逻辑。异常处理完毕后,会继续执行异常代码块后面的代码(如果有)。
以上只是对项目中的一些经验的小结,可能存在不正确的地方,请多包涵。