# 从ORA报错到KES跑通:Oracle迁移三大痛点与代码实测
**Oracle迁移金仓KES,最怕的不是数据量,而是那些在Oracle里跑了好几年、谁都不敢动的“祖 传代码”**。
某政务系统迁移项目中,DBA信心满满地跑完KDMS评估——兼容度98%。上线前夜,一个用了八年的存储过程突然报错:`ERROR: function regexp_substr(text, text) does not exist`。开发已经下班,业务方在催,问题根源只是**一个Oracle私藏的函数KES也有,但函数名多了个前缀**。
本文整理Oracle→KES迁移实战中**最高频的三个语法痛点**,每个痛点均附带**报错原文、错误根因、实测可用的解决方案**。
## 痛点一:正则函数家族——同名不同姓
**报错原文**:
```
ERROR: function regexp_substr(text, text) does not exist
Hint: No function matches the given name and argument types.
```
**根因分析**:
Oracle内置`regexp_substr`、`regexp_replace`、`regexp_instr`、`regexp_count`四个正则函数。**金仓KES的Oracle兼容模式下确实支持这些函数,但函数名带模式前缀**。直接调用`regexp_substr`会误认PostgreSQL原生正则函数,参数不匹配导致报错。
**解决方案(三选一)**:
**方案A:使用带模式名的完整函数名(推荐)**
```sql
-- Oracle写法
SELECT regexp_substr('abc123def', '[0-9]+') FROM dual;
-- KES兼容写法
SELECT oracle.regexp_substr('abc123def', '[0-9]+') FROM dual;
```
**实测**:显式指定`oracle.`前缀,彻底规避函数名解析歧义。
**方案B:修改search_path优先加载oracle模式**
```sql
SET search_path TO oracle, public, pg_catalog;
```
修改后直接调用`regexp_substr`即可命中oracle模式下的同名函数。
**方案C:创建自定义封装函数**
```sql
CREATE OR REPLACE FUNCTION regexp_substr(text, text)
RETURNS text AS $$
SELECT oracle.regexp_substr($1, $2);
$$ LANGUAGE sql STRICT IMMUTABLE;
```
**适用场景**:遗留代码量过大,无法逐条修改;第三方应用硬编码SQL。
## 痛点二:层次查询CONNECT BY——PRIOR操作符歧义
**报错原文**:
```
ERROR: syntax error at or near "PRIOR"
LINE 3: CONNECT BY PRIOR employee_id = manager_id
^
```
**根因分析**:
Oracle的`CONNECT BY PRIOR`是层次查询标准语法。**金仓KES通过oracle兼容模式完整支持CONNECT BY,但PRIOR操作符必须紧贴列名,不能出现`PRIOR employee_id = manager_id`这种左右分离写法**。
**解决方案(语法微调)**:
```sql
-- Oracle原写法(报错)
SELECT employee_id, manager_id, level
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;
<"g6.p5k3.org.cn">
<"q3.p5k3.org.cn">
<"t7.p5k3.org.cn">
-- KES兼容写法(PRIOR紧贴对应列)
SELECT employee_id, manager_id, level
FROM employees
START WITH manager_id IS NULL
CONNECT BY employee_id = PRIOR manager_id; -- PRIOR移至右侧
```
**实测结论**:**KES的CONNECT BY执行计划与Oracle基本一致,仅PRIOR操作符位置需右置**。此规则一旦记住,再无类似报错。
## 痛点三:NULL排序行为——排序语义差异
**业务表现**:
原Oracle系统中“按更新时间倒序”的查询,迁移后**NULL值排在结果集最前面**,业务方质疑“最新数据怎么没了”。
**根因分析**:
- **Oracle排序默认**:`ORDER BY col ASC` → NULL值最后;`ORDER BY col DESC` → NULL值最前
- **KES/PostgreSQL排序默认**:`ASC/DESC`均将NULL值视作“无穷大”,DESC时NULL最前,ASC时NULL最后
**Oracle用户真实预期**:无论升序降序,NULL值永远排在最后。
**解决方案(显式控制NULLS位置)**:
```sql
-- 方案A:添加NULLS LAST指令(推荐)
SELECT * FROM audit_log
ORDER BY update_time DESC NULLS LAST;
-- 方案B:利用COALESCE兜底(索引友好)
SELECT * FROM audit_log
ORDER BY COALESCE(update_time, '1970-01-01') DESC;
-- 方案C:会话级参数调整(谨慎使用)
SET enable_sort_with_nulls_position = 'END';
```
**实测**:方案A兼容性最好,Oracle同样支持`NULLS LAST`语法,迁移后无需回退。
<"wang.p5k3.org.cn">
<"zi.p5k3.org.cn">
<"xixi.p5k3.org.cn">
## 痛点四(附加):高级包DBMS_XXX——需要显式安装
**报错原文**:
```
ERROR: schema "dbms_output" does not exist
```
**根因分析**:
Oracle的`DBMS_OUTPUT`、`DBMS_LOB`、`DBMS_RANDOM`等高级包在KES中**并非默认安装**,需手动创建扩展。
**解决方案**:
```sql
-- 安装高级包扩展
CREATE EXTENSION IF NOT EXISTS dbms_output;
CREATE EXTENSION IF NOT EXISTS dbms_lob;
CREATE EXTENSION IF NOT EXISTS dbms_random;
CREATE EXTENSION IF NOT EXISTS dbms_sql;
-- 验证安装
SELECT oracle.dbms_output.put_line('Hello KES');
```
**注意事项**:高级包函数均在`oracle`模式下,调用需带`oracle.`前缀或提前设置`search_path`。
## 避坑配置检查清单(迁移前必做)
**1. 大小写敏感模式**
Oracle默认大小写不敏感,KES默认敏感。初始化时务必指定:
```bash
./initdb -D /data --case-insensitive
```
**2. 日期格式统一**
Oracle常用`DD-MON-YY`,KES建议统一为ISO格式:
```sql
ALTER SYSTEM SET datestyle = 'ISO, YMD';
```
**3. OID列支持(ROWID模拟)**
若应用使用Oracle的`ROWID`伪列,需启用表级OID:
```sql
SET default_with_oids = on; -- 建表前执行
```
**Oracle迁移KES,99%的代码可以零修改跑通——但剩下的1%如果不提前识别,就会变成上线前夜的100%焦虑**。正则函数加前缀、CONNECT BY右置PRIOR、NULL排序显式声明,这三条规则记住了,迁移路上80%的语法报错都不会再遇到第二次。