今天PMO下达任务单,校讯通数据库从sybase系统改造到oracle系统,进行了对象的总计有312张实体表,20个过程,通过手工敲,那肯定是猴年马月的事情,不符合项目任务的工期进度。以下是本次转化的快捷方法:
1、通过powerdesigner的Change Current DBMS操作。
new dbms 选择ORACLE Version 10gR2替换current dbms的Sybase AS Enterprise 12.5.3a。
符合期望的:通过此步操作char、varchar、numeric、datetime转向了我们期望的char、varchar2、number、date。
不符合期望的:integer没有转向我们期望的number,默认值getdate()没有转向我们期望的SYSDATE,default ''没有转为有效的default ' '。针对oracle 空串是无效的。索引名保留了sybase特性,对象中唯一,却没有符合oracle的全局唯一。过程那是原原本本保留了sybase的脚本。
2、开始针对不符合期望的改造工作
校讯通数据库设计文档是用powerdesigner15版本设计的,可以直接通过编辑工具editplus,UltraEdit打开,本质上是xml文件,然后查找integer类型定义关键字串。
类型定义:<a:DataType>INTEGER</a:DataType> 统一修改成了<a:DataType>NUMBER(10)</a:DataType>。
针对本质是布尔类型,是和否的判断的,显然NUMBER(1)就行,在定义此类字段名时有显著特征is_开头,通过EltraEdit打开找到<a:Code>is_字符串,在此字符串附近定位到针对这个字段的类型定义,由于做了前面步骤,都已经改成了NUMBER(10)统一改为NUMBER(1),针对其他字段,虽然可能有的字段长度不需要10,个别对待修改。
默认值定义:<a:DefaultValue>getdate()</a:DefaultValue>统一修改成了<a:DefaultValue>SYSDATE</a:DefaultValue>,在sybase中的default ''后来经分析确认,通过编辑工具打xml真实定义是<a:DefaultValue>''</a:DefaultValue>统一修改成了<a:DefaultValue>' '</a:DefaultValue>中间加入一空格,Oracle可以支持。
做了以上两步之后,表对象定义的类型以及默认值都符合了期望,至于索引名称由于要全局唯一,只能通过手工修改了,包括过程也是。通过统一替换已经给我们节省了不少时间,赶上项目任务单的计划进度不成问题了。其他类型的数据库设计文档的DBMS转换可以参考类似。
修改的规范参见我的blog:数据库设计规范
http://blog.csdn.net/xujinyang/article/details/6977149
3、针对原设计文档gbk字符集转为utf8的修改
通过分析gbk字符集转为utf8主要焦点是针对varchar2类型的字段长度原理上以1.5倍扩展,因为gbk字符集特殊字符以及汉字类占两个字节,而utf8占3个字节,为此特编写了两个过程:
1)针对数据库设计文档pdm的修改过程:up_modify_pdm
CREATE OR REPLACE PROCEDURE up_modify_pdm
(
var_filepath IN varchar2
,var_filename IN varchar2,
var_maxnum IN NUMBER
)
is
var_in_str VARCHAR2(32767);
var_out_str VARCHAR2(32767);
var_in_file UTL_FILE.FILE_TYPE;
var_out_file UTL_FILE.FILE_TYPE;
var_i number:=0;
var_j number:=0;
var_len varchar2(10);
begin
var_in_file := UTL_FILE.FOPEN(var_filepath,var_filename,'R',var_maxnum);
var_out_file:= UTL_FILE.FOPEN(var_filepath,'new_'||var_filename,'W',var_maxnum);
loop
var_i:=var_i+1;
UTL_FILE.GET_LINE(var_in_file,var_in_str);
if substr(var_in_str,1,21) = '<a:DataType>VARCHAR2(' then
var_j:=var_i;
var_len := substr(var_in_str,22,instr(var_in_str,')',22,1) - 22);
var_out_str:='<a:DataType>VARCHAR2('||to_char(ceil(to_number(var_len)*1.5))||')</a:DataType>';
UTL_FILE.PUT_LINE(var_out_file,var_out_str);
elsif var_i=var_j+1 and substr(var_in_str,1,10) = '<a:Length>' then
var_len := substr(var_in_str,11,instr(var_in_str,')',11,1) - 11);
var_out_str:='<a:Length>'||to_char(ceil(to_number(var_len)*1.5))||'</a:Length>';
UTL_FILE.PUT_LINE(var_out_file,var_out_str);
else
var_out_str:=var_in_str;
UTL_FILE.PUT_LINE(var_out_file,var_out_str);
end if;
end loop;
EXCEPTION
WHEN NO_DATA_FOUND THEN
begin
UTL_FILE.FCLOSE(var_in_file);
UTL_FILE.FCLOSE(var_out_file);
end;
when others then
begin
dbms_output.put_line(sqlerrm||':'||var_in_str);
UTL_FILE.FCLOSE(var_in_file);
UTL_FILE.FCLOSE(var_out_file);
end;
END up_modify_pdm;
2)针对数据库中已经创建表对象的长度修改:up_modify_col_length
create or replace procedure up_modify_col_length
is
var_tab varchar2(30);
var_len number(10);
var_sql varchar2(2000) :=' ';
i number(10);
begin
dbms_output.enable(50000);
declare type tab_col is record(tab_name varchar2(30),col_name varchar2(30),data_len number(10));
type type_array is table of tab_col index by binary_integer;
var_array type_array;
begin
select col.TABLE_NAME,col.COLUMN_NAME,col.DATA_LENGTH bulk collect into var_array
from USER_TAB_COLUMNS col,USER_TABLES tab
where col.TABLE_NAME=tab.TABLE_NAME and col.DATA_TYPE='VARCHAR2' order by col.TABLE_NAME;
var_tab := var_array(1).tab_name;
var_len := Ceil(var_array(1).data_len*1.5);
if var_len<=4000 then
var_sql := 'alter table '||var_tab||' modify ('||var_array(1).col_name||' VARCHAR2('||to_char(var_len)||')';
else
dbms_output.put_line(var_tab||'.'||var_array(1).col_name||' length*1.5='||to_char(var_len)||' will be more than 4000');
end if;
for i in 2..var_array.count loop
begin
if var_array(i).tab_name != var_tab then
if var_sql != ' ' then
var_sql := var_sql||')';
var_sql := ltrim(var_sql);
if substr(var_sql,1,1) = ',' then
var_sql := substr(var_sql,2);
var_sql := 'alter table '||var_tab||' modify ('|| var_sql;
end if;
begin
execute immediate var_sql;
exception
when others then
begin
dbms_output.put_line(sqlerrm||':'||var_sql);
return;
end;
end;
end if;
var_sql := ' ';
end if;
var_len := Ceil(var_array(i).data_len*1.5);
if var_len > 4000 then
dbms_output.put_line(var_array(i).tab_name||'.'||var_array(i).col_name||' length*1.5='||to_char(var_len)||' will be more than 4000');
else
if var_array(i).tab_name != var_tab then
var_sql := 'alter table '||var_array(i).tab_name||' modify ('||var_array(i).col_name||' VARCHAR2('||to_char(var_len)||')';
else
var_sql := var_sql||','||var_array(i).col_name||' VARCHAR2('||to_char(var_len)||')';
end if;
end if;
--dbms_output.put_line(var_array(i).tab_name||','||var_array(i).col_name||','||to_char(var_array(i).data_len));
var_tab := var_array(i).tab_name;
end;
end loop;
if var_sql != ' ' then
var_sql := var_sql||')';
var_sql := ltrim(var_sql);
if substr(var_sql,1,1) = ',' then
var_sql := substr(var_sql,2);
var_sql := 'alter table '||var_tab||' modify ('|| var_sql;
end if;
begin
execute immediate var_sql;
exception
when others then
begin
dbms_output.put_line(sqlerrm||':'||var_sql);
return;
end;
end;
end if;
end;
end up_modify_col_length;