【IT168 技术】为了使得将数据库和应用程序从Oracle数据库产品迁移到IBM DB2更方便,本文具体探讨在迁移过程中的一些常见问题以及,ORACLE数据库移植到DB2中的变量定义、空值处理、隐形转换、时间函数及DECODE函数的解决。
变量定义和BEGIN END
DB2中变量定义在BEGIN END体内,并且每个变量都要用DECLARE声明;存储过程结束时,END后跟P1,并且不需要分号。
Oracle中变量定义必须在BEGIN END体外,变量都不需要用DECLARE声明(有种说法是,第一个变量需要DECLARE,其他变量不需要);存储过程结束时,END后跟存储过程的名称,并且需要分号。
DB2:
CREATEPROCEDUREPRO1()
LANGUAGE SQL
P1:BEGIN--变量定义DECLAREINSERT_DATETIMESTAMP;DECLAREALLDEPT_NOVARCHAR(20);--具体操作SELECTaFROMTAB_1;
.........ENDP1
Oracle:
CREATEPROCEDUREPRO1IS--变量定义INSERT_DATETIMESTAMP;
ALLDEPT_NOVARCHAR(20);BEGIN--具体操作SELECTaFROMTAB_1;
.........ENDPRO1;
空值的处理
Oracle空值处理通过 nvl 函数实现,DB2中通过COALESCE函数实现。在DB2 V9.5中已经实现了 NVL 函数。
在Oracle中,对于null数据的处理比较灵活,在与NULL值进行比较和拼接时与DB2的结果完全不同,例如:
SELECT'abc'||c1FROMt1 (c1ISNULL)
ORACLE得到 abc 的结果。
在DB2中为null,要想得到 abc 的结果,按照如下语法修改,
SELECT'abc‘ || COALESCE(c1,'') FROM t1
还有在Oracle中select * from table where id = null这种语法是允许的,在DB2中不可。但需要说明的是在Oracle中虽然select * from table where id = null是可以通过语法检查,但与select * from table where id is null语句得到结果集是不同的,所以在移植时要考虑真实的业务意义,在翻译成DB2的语法。
另外有些应用有如下用法:
SELECT*FROMTABLEWHERE(''ISNULLORIDisnull)AND(''ISNULLORNAME='')ANDNUM='0'
在DB2中可翻译为:
SELECT*FROMTABLEWHERE(cast(nullasvarchar(10))ISNULLORIDisnull)AND(cast(nullasvarchar(10))ISNULLORNAMEisnull)ANDNUM='0'
隐形转换处理
在程序迁移过程中我们需要注意一点的是:Oracle支持数据类型之间的隐形转化,而DB2是不支持数据这个特性的,因此在使用SQL进行数据查询或更新时必须配置字段的类型。
例如:在表中employee 字段empno 定义为数字类型:
select*fromemployeewhereempno='1010';
该语句在oracle数据库环境可执行通过,但在DB2下报错:
SQLCODE: -408, SQLSTATE: 42821。
修正为:
select*fromemployeewhereempno=1010;
如果在程序中使用变量,可以使用cast关键字进行数据类型转换工作。语法如下:
select*fromemployeewhereempno=cast(V_nameasbigint)select*fromemployeewhereempno=cast(V_nameasvarchar(10))
以上主要讲了Oracle向DB2迁移的3种常见问题的处理,下面引用 IBM高级工程师 戴慰 的一篇文章《从Oracle数据库移植到 DB2 V9.1 过程中几个关键性函数的实现》的里面的2种常见关键性函数的解决方法。
日期时间函数的实现
Oracle采用SYSDATE作为取当前时间,而DB2中采用CURRENTTIMESTAMP获得当前时间,为了减少代码的修改量,我们编写SYSDATE的UDF函数,只需要在SYSDATE后面增加双括号,既然由Oracle中的Sysdate修改成Sysdate(),即可以调用新编写的SYSDATE()函数,见下载章节中的SYSDATE函数。
CREATEFUNCTIONsysdate()RETURNStimestampLANGUAGE SQLBEGINATOMICRETURN(currenttimestamp);END!
DECODE函数的实现
Oracle的Decode是多值判断函数,该函数有Oracle内核进行解析和判断,不属于普通的用户函数,所以DECODE对传入的调制值和返回值都可以动态调用。DECODE函数的应用非常广泛,DECODE(条件值1,返回值1,值2,返回值2,……值n,返回值n,缺省值),该函数的内容逻辑如下:
IF条件=值1THENRETURN( 返回值1)IF条件=值2THENRETURN( 返回值2)
......IF条件=值 nTHENRETURN( 返回值 n)ELSERETURN( 缺省值 )
从DECODE函数代码逻辑来看,DECODE的内部的原理非常的简单,难点就是在于如何解决DOUBLE,DATE,TIMESTAMPL等不同的参数数据类型和不同的返回数据类型。由于DECODE是ORACLE数锯库的内部函数,ORACLE内部的实现机制不得而知,如果想在DB2内实现如下功能必须利用UDF的可重载的特性。
IBM的基本的数据类型包括CHAR()、VarChar()、SMALLINT、INTEGER、BIGINT、DECIMAL、REAL、DOUBLE、DATE、TIME、TIMESTAMP数据类型,DECODE的函数的条件值和判断值的数据类型一致,但返回数据类型可以和条件值不同,按照排列组合的规律来看,输入、输出数据类型的组合式11n,当N>3以上,由于代础最和组合次数过多,很难采用手工写程序的方式来实现。
为丁解决这个难题,我们想到了采用代码生成机来实现所有的组合,考虑到使用的方便和跨平台,采用JAVA程序开发GenDecode的生成程序,具体执行过程中只需输入预计最大的DECODE的参数数量,GenDecode按照数据组合的顺序,逐步把所有的参数类犁的组合全部生成出来,并且导入到文件中,以下是GenDecode的主要功能函数:
//根据给定的参数值,生成各种组合的 DECODE 函数
private void GenDecode(intintMaxInputNumber) {
String strFlagType="";
String strReturnType="";
String strBuffer="";//DB2 数据类型
String[]strType=new String[11];
strType[0]="CHAR(128)";
strType[1]="VarChar(512)";
strType[2]="SMALLINT";
strType[3]="INTEGER";
strType[4]="BIGINT";
strType[5]="DECIMAL";
strType[6]="REAL";
strType[7]="DOUBLE";
strType[8]="DATE";
strType[9]="TIME";
strType[10]="TIMESTAMP";intm=0, n=0, intMax=3;while(intMax<=intMaxInputNumber) {
m=0;
n=0;while(m<11) {
n=0;
strFlagType=strType[m];while(n<11) {
strReturnType=strType[n];//生产 DB2 UDF DECODE 的函数头
strBuffer+=GenInputVal(intMax, strFlagType, strReturnType);//生成 DB2 UDF DECODE 的函数体
strBuffer+=GenWhenElse(intMax);//把生产的代码写入文件
WrtDecode(strBuffer);
strBuffer="";
n++;
}
m++;
}
intMax++;
}
}
通过GenDecode生产的DECODE函数的例子,在下载中您可以下载已经生成1到35个参数的DECODE函数,见下载章节中的DECODE.SQL函数。CREATEFUNCTIONDECODE(P0SMALLINT,P1SMALLINT,
P2 TIME,P3SMALLINT,P4 TIME)RETURNSTIME
LANGUAGE SQLBEGINATOMICRETURN(CASEP0WHENP1THENP2WHENP3THENP4END);END!
总 结
本文展示了一些SQL开发的用户定义函数(UDF)以实现ORACLE中的若干关键性函数。如果你对确切的实现细节很感兴趣,可以查阅这些代码。一旦变异?并连接了源代码(或安装了预编译的库)以及在数据库中注册了这些过程和函数之后,就可以按本文示例所演示的那样来使用它们了。另外值得注意的是,这些过程和函数已经在DB2 UDB v9.1平台被编译和执行过。