【IT168 技术】为了使得将数据库和应用程序从Oracle数据库产品迁移到IBM DB2更方便,本文具体探讨在迁移过程中的一些常见问题以及,ORACLE数据库移植到DB2中的变量定义、空值处理、隐形转换、时间函数及DECODE函数的解决。
变量定义和BEGIN END
DB2中变量定义在BEGIN END体内,并且每个变量都要用DECLARE声明;存储过程结束时,END后跟P1,并且不需要分号。
Oracle中变量定义必须在BEGIN END体外,变量都不需要用DECLARE声明(有种说法是,第一个变量需要DECLARE,其他变量不需要);存储过程结束时,END后跟存储过程的名称,并且需要分号。
DB2:
LANGUAGE SQL
P1: BEGIN
--变量定义
DECLARE INSERT_DATE TIMESTAMP;
DECLARE ALLDEPT_NO VARCHAR(20);
--具体操作
SELECT a FROM TAB_1;
.........
END P1
Oracle:
IS
--变量定义
INSERT_DATE TIMESTAMP;
ALLDEPT_NO VARCHAR(20);
BEGIN
--具体操作
SELECT a FROM TAB_1;
.........
END PRO1;
空值的处理
Oracle空值处理通过 nvl 函数实现,DB2中通过COALESCE函数实现。在DB2 V9.5中已经实现了 NVL 函数。
在Oracle中,对于null数据的处理比较灵活,在与NULL值进行比较和拼接时与DB2的结果完全不同,例如:
ORACLE得到 abc 的结果。
在DB2中为null,要想得到 abc 的结果,按照如下语法修改,
还有在Oracle中select * from table where id = null这种语法是允许的,在DB2中不可。但需要说明的是在Oracle中虽然select * from table where id = null是可以通过语法检查,但与select * from table where id is null语句得到结果集是不同的,所以在移植时要考虑真实的业务意义,在翻译成DB2的语法。
另外有些应用有如下用法:
在DB2中可翻译为:
隐形转换处理
在程序迁移过程中我们需要注意一点的是:Oracle支持数据类型之间的隐形转化,而DB2是不支持数据这个特性的,因此在使用SQL进行数据查询或更新时必须配置字段的类型。
例如:在表中employee 字段empno 定义为数字类型:
该语句在oracle数据库环境可执行通过,但在DB2下报错:
SQLCODE: -408, SQLSTATE: 42821。
修正为:
如果在程序中使用变量,可以使用cast关键字进行数据类型转换工作。语法如下:
select * from employee where empno =cast(V_name as varchar(10))
以上主要讲了Oracle向DB2迁移的3种常见问题的处理,下面引用 IBM高级工程师 戴慰 的一篇文章《从Oracle数据库移植到 DB2 V9.1 过程中几个关键性函数的实现》的里面的2种常见关键性函数的解决方法。
日期时间函数的实现
Oracle采用SYSDATE作为取当前时间,而DB2中采用CURRENTTIMESTAMP获得当前时间,为了减少代码的修改量,我们编写SYSDATE的UDF函数,只需要在SYSDATE后面增加双括号,既然由Oracle中的Sysdate修改成Sysdate(),即可以调用新编写的SYSDATE()函数,见下载章节中的SYSDATE函数。
RETURNS timestamp
LANGUAGE SQL
BEGIN ATOMIC
RETURN
(
current timestamp
);
END
!
DECODE函数的实现
Oracle的Decode是多值判断函数,该函数有Oracle内核进行解析和判断,不属于普通的用户函数,所以DECODE对传入的调制值和返回值都可以动态调用。DECODE函数的应用非常广泛,DECODE(条件值1,返回值1,值2,返回值2,……值n,返回值n,缺省值),该函数的内容逻辑如下:
IF 条件 = 值 2 THEN RETURN( 返回值 2)
......
IF 条件 = 值 n THEN RETURN( 返回值 n)
ELSE RETURN( 缺省值 )
从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的主要功能函数:
private void GenDecode(int intMaxInputNumber) {
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";
int m = 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函数。
CREATE FUNCTION DECODE(P0 SMALLINT,P1 SMALLINT,
P2 TIME,P3 SMALLINT,P4 TIME)
RETURNS TIME
LANGUAGE SQL
BEGIN ATOMIC
RETURN
(
CASE P0
WHEN P1 THEN P2
WHEN P3 THEN P4
END
);
END
!
总 结
本文展示了一些SQL开发的用户定义函数(UDF)以实现ORACLE中的若干关键性函数。如果你对确切的实现细节很感兴趣,可以查阅这些代码。一旦变异?并连接了源代码(或安装了预编译的库)以及在数据库中注册了这些过程和函数之后,就可以按本文示例所演示的那样来使用它们了。另外值得注意的是,这些过程和函数已经在DB2 UDB v9.1平台被编译和执行过。