Oracle迁移到信创数据库——从数据字典自动生成DDL的完整方案
Oracle迁移到信创数据库——从数据字典自动生成DDL的完整方案
信创迁移不是"导出再导入"那么简单。Oracle有 VARCHAR2、NUMBER、CLOB,达梦和人大金仓有自己的类型体系。逐张表手工改写DDL?几百张表写到明年。这篇记录的是一套从Oracle数据字典自动读取表结构、自动转换数据类型、自动生成目标库DDL的方案——不是书上看的,是从迁移一线下来的实战经验。
文章目录
一、信创迁移不是"换个数据库"
信创迁移的目标是把Oracle换成国产数据库——达梦、人大金仓、GBase。很多人以为迁移就是 expdp 导出 → impdp 导入。
不是。因为:
- 数据类型不一样——Oracle的
VARCHAR2到达梦是VARCHAR,NUMBER如果精度小于18且scale为0应该转成INT而不是DECIMAL - 建表语法不一样——Oracle的
SEGMENT CREATION IMMEDIATE到了金仓根本没有这个概念 - 存储过程不兼容——PL/SQL和达梦的SQL语法有大量差异,不是改几个关键字就能跑的
- 序列、触发器、视图——这些对象的迁移语法差异更大
几百张表,手工改写DDL不现实。几十个存储过程,逐行改写更不现实。必须有一套自动化方案——从Oracle的数据字典里读取所有对象的定义,自动转换为目标库的语法。
二、第一步:从数据字典自动生成建表DDL
Oracle的数据字典 dba_tab_columns 存了所有表的列定义——列名、数据类型、长度、精度、是否可空。核心思路是遍历这个字典,拼出目标库的CREATE TABLE语句。
DECLARE
n_count NUMBER;
n_row NUMBER := 0;
BEGIN
-- 遍历指定用户下的所有表
FOR rec IN (SELECT * FROM dba_tables t
WHERE t.OWNER = 'CORE'
ORDER BY t.TABLE_NAME)
LOOP
dbms_output.put_line('CREATE TABLE ' || rec.table_name || '(');
n_count := 0;
n_row := 0;
SELECT COUNT(*) INTO n_count
FROM dba_tab_columns t
WHERE t.OWNER = rec.owner
AND t.TABLE_NAME = rec.table_name;
-- 遍历每一列,按Oracle类型转换为目标库类型
FOR rec1 IN (SELECT * FROM dba_tab_columns t
WHERE t.OWNER = rec.owner
AND t.TABLE_NAME = rec.table_name)
LOOP
n_row := n_row + 1;
dbms_output.put(' ' || rec1.column_name);
-- 类型映射:Oracle → SQL Server/达梦/金仓
IF rec1.data_type = 'VARCHAR2' THEN
dbms_output.put(' VARCHAR(' || rec1.data_length || ')');
ELSIF rec1.data_type = 'NUMBER' THEN
IF rec1.data_precision < 18 AND rec1.data_scale = 0 THEN
dbms_output.put(' INT');
ELSIF rec1.data_scale > 0 THEN
dbms_output.put(' DECIMAL(' || rec1.data_precision || ','
|| rec1.data_scale || ')');
ELSE
dbms_output.put(' BIGINT');
END IF;
ELSIF rec1.data_type = 'DATE' THEN
dbms_output.put(' DATETIME');
ELSIF rec1.data_type = 'CLOB' THEN
dbms_output.put(' TEXT');
ELSIF rec1.data_type = 'NVARCHAR2' THEN
dbms_output.put(' VARCHAR(' || rec1.data_length || ')');
END IF;
-- 非空约束
IF rec1.nullable = 'N' THEN
dbms_output.put(' NOT NULL');
END IF;
IF n_row < n_count THEN
dbms_output.put_line(',');
END IF;
END LOOP;
dbms_output.put_line(');');
-- 提取主键约束
FOR rec2 IN (SELECT * FROM sys.user_constraints t
WHERE t.constraint_type = 'P'
AND t.owner = rec.owner
AND t.table_name = rec.table_name)
LOOP
dbms_output.put('ALTER TABLE ' || rec2.table_name
|| ' ADD CONSTRAINT ' || rec2.constraint_name
|| ' PRIMARY KEY (');
-- 提取主键列...
n_count := 0;
SELECT COUNT(*) INTO n_count
FROM sys.user_cons_columns
WHERE constraint_name = rec2.constraint_name;
-- 逐列拼主键...
dbms_output.put_line(');');
END LOOP;
END LOOP;
END;
只跑了 ACT_RE_BINDINGFORM 这一张表来验证逻辑——把生成的SQL复制到目标库执行,表结构完全正确。后面的表按同样逻辑批量生成,几百张表半小时全部出完。
三、类型映射的核心规则
Oracle和国产库的类型不是一一对应的。映射错了,数据精度丢失、日期格式乱码、主键约束建不上。
| Oracle类型 | SQL Server | 达梦 | 判断逻辑 |
|---|---|---|---|
| VARCHAR2(N) | VARCHAR(N) | VARCHAR(N) | 直接映射 |
| NUMBER(p,0) 且 p<18 | INT | INT | 整数且不超精度 |
| NUMBER(p,s) 且 s>0 | DECIMAL(p,s) | DECIMAL(p,s) | 有小数位 |
| NUMBER(p,0) 且 p>=18 | BIGINT | BIGINT | 长整型 |
| DATE | DATETIME | DATETIME | 日期时间 |
| CLOB | TEXT | TEXT | 大文本 |
| NVARCHAR2 | VARCHAR | VARCHAR | 去掉N前缀 |
关键判断在 NUMBER 类型的分支逻辑——同一个 NUMBER,根据 DATA_PRECISION 和 DATA_SCALE 的不同组合,映射到三种完全不同的目标类型。这是手写DDL最容易出错的地方——少了一个判定分支,INT变成了DECIMAL,精度就丢了。
四、不只是建表——其他对象的迁移
表结构只是迁移的第一步。完整的数据库迁移还包括:
索引:从 dba_indexes 和 dba_ind_columns 读取索引定义,生成对应的 CREATE INDEX 语句。注意Oracle的位图索引到达梦可能不支持,需要改写成B-Tree索引。
序列:CREATE SEQUENCE 在Oracle、达梦、金仓之间的语法基本一致,但 NOCACHE / CACHE 的定义有差异。从 dba_sequences 读取当前值,迁移后需要把序列的当前值设回去——否则新插入数据的主键会冲突。
视图:从 dba_views 读取视图定义的TEXT字段。但Oracle的视图里可能有 DECODE、CONNECT BY 这些Oracle独有的函数和语法——直接复制到目标库大概率报错。需要逐条检查,替换成目标库等价的函数。
存储过程:这是最难的部分。Oracle的PL/SQL和达梦的SQL在游标声明、异常处理、BULK COLLECT 等方面语法差异巨大。没有自动化工具能做完整的PL/SQL→目标库语法转换——只能逐行改写。
五、迁移策略:分步走,每步验证
第一步:导出Oracle表结构 → 自动生成目标库DDL
└── 验证:在目标库执行DDL,确认所有表建成且无语法错误
第二步:导出索引、序列、视图 → 自动生成目标库DDL
└── 验证:索引是否全建、序列从当前值开始、视图能编译通过
第三步:数据迁移(DBLink直抽或导出导入)
└── 验证:行数比对、主键唯一性检查、日期字段无乱码
第四步:存储过程——人工逐行改写
└── 验证:单元测试覆盖核心业务逻辑
第五步:应用层改造——JDBC驱动替换、SQL方言适配
└── 验证:全链路回归测试
不能在第一步还没验证完的时候就跳到第三步——如果表的字段类型映射错了,导入了数据之后才发现,已经晚了。
关键原则:每个阶段都做一次验证再进入下一阶段。 不是一口气全干完然后祈祷没有问题。
六、亮点总结
✅ 数据字典驱动——从 dba_tab_columns 自动读取几百张表的结构,不手工改一行DDL
✅ 类型映射完备——NUMBER按精度和scale三分支映射,区分INT/DECIMAL/BIGINT
✅ 约束自动迁移——主键、非空从数据字典自动生成,不会漏
✅ 分步验证——建表→索引→序列→数据→存储过程,每步验证后再进行下一步
✅ 可反向操作——同样的逻辑反过来也可以把目标库的表结构导出为Oracle DDL
七、适用场景
- Oracle到达梦/人大金仓/GBase的信创迁移
- 任何需要"从数据字典反推DDL"的场景——不仅仅是信创,数据库版本升级、跨平台迁移都适用
- 几百张表需要批量生成建表语句,手工改写不现实的项目
八、扩展方向
- 完整DDL生成——增加索引、序列、视图、触发器的自动生成逻辑
- PL/SQL语法自动检查——扫描存储过程中Oracle独有的语法,标记需要人工改写的部分
- 迁移报告——对比源库和目标库的表结构差异,生成迁移对照清单
九、结语
信创迁移最大的工作量不是"数据怎么搬过去"——expdp/impdp 现成的工具多的是。最大头是表结构、索引、视图、存储过程的语法改写——几百张表的DDL要逐行改写成目标库的语法。
从数据字典里批量读出来、自动生成DDL——这个思路本身就是信创迁移里的核心经验。不是"会写SQL"能搞定的事,是"知道从哪取元数据、怎么映射类型、怎么分步验证"的系统性认知。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)