导出SQL至Oracle需手动映射字段类型:VARCHAR→VARCHAR2(255),INT等→NUMBER,DATETIME→TIMESTAMP,BOOLEAN→CHAR(1)/NUMBER(1)加CHECK;删IF NOT EXISTS;DEFAULT用SYSDATE/SYSTIMESTAMP或TO_DATE;约束名≤30字符且唯一。
导出 SQL 时字段类型要手动映射到 Oracle 支持的类型
mysql 的 varchar(255) 或 postgresql 的 text 直接扔进 oracle 会报错,oracle 没有无长度限制的 varchar,text 也不是原生类型。常见错误现象是 ora-00906: missing left parenthesis 或 ora-00907: missing right parenthesis,本质是类型语法不识别。
实操建议:
-
VARCHAR→ 统一改写为VARCHAR2(255)(注意 Oracle 最大支持 4000 字节,超长用CLOB) -
INT/TINYINT/BIGINT→ 全部映射为NUMBER(10)或更宽泛的NUMBER(Oracle 没有带符号整型区分) -
DATETIME/TIMESTAMP WITHOUT TIME ZONE→ 改成TIMESTAMP(Oracle 默认含秒级精度,但不自动存时区) -
BOOLEAN→ Oracle 没原生布尔类型,得用CHAR(1)或NUMBER(1),并加CHECK (col IN ('Y','N'))约束
CREATE TABLE 语句里不能有 IF NOT EXISTS
MySQL/PostgreSQL 导出的建表语句常带 IF NOT EXISTS,Oracle 会直接报 ORA-00922: missing or invalid option。这不是兼容性“选项”问题,而是语法根本不存在。
实操建议:
- 全局搜索替换掉所有
IF NOT EXISTS,连同前面的空格和括号一起删干净 - 不要试图用
CREATE OR REPLACE替代——它只适用于视图、存储过程等,对表无效 - 如果需要幂等建表,得先写 PL/SQL 块查
USER_TABLES表,再动态执行,但那是导入脚本的事,不是导出阶段该处理的
默认值写法必须符合 Oracle 的表达式规则
MySQL 写 DEFAULT CURRENT_TIMESTAMP,PostgreSQL 写 DEFAULT now(),Oracle 会报 ORA-00984: column not allowed here。Oracle 要求默认值是字面量或带括号的函数调用,且函数必须是确定性的(SYSDATE 可以,NOW() 不行)。
实操建议:
-
CURRENT_TIMESTAMP→ 改成SYSTIMESTAMP(带时区)或SYSDATE(不带时区) -
DEFAULT '2023-01-01'→ 必须显式转日期:DEFAULT TO_DATE('2023-01-01', 'YYYY-MM-DD') -
DEFAULT 1可以保留,但DEFAULT true必须改成DEFAULT 'Y'或DEFAULT 1(取决于字段定义) - 字符串默认值里的单引号要双写:
DEFAULT 'O''Reilly'
导出后必须测试约束名长度和唯一性
Oracle 对约束名有 30 字符硬限制,且同一 schema 下不能重名。导出工具(如 mysqldump、pg_dump)生成的约束名常带长前缀或哈希,比如 fk_user_profile_user_id_7f8b3a2c,直接导入会触发 ORA-00972: identifier is too long。
实操建议:
- 提前用正则批量截断约束名,保留有意义前缀 + 下划线 + 6 位简写,例如
fk_user_prof_usr_id_7f8b3a - 主键名别都叫
PRIMARY,Oracle 要求显式命名,建议统一用pk_table_name - 外键名重复概率高,尤其多表关联时,检查
USER_CONSTRAINTS视图确认无冲突再跑 DDL
真正麻烦的不是语法转换,是那些隐式依赖:比如 MySQL 自增用 AUTO_INCREMENT,Oracle 得靠序列 + 触发器模拟;又比如大小写敏感策略不同,导出时没加双引号的标识符,进 Oracle 就全变大写了。这些不在 DDL 里明写,但漏了就卡在数据插入阶段。











