从ORA报错到KES跑通:Oracle迁移三大痛点与代码实测

# 从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%的语法报错都不会再遇到第二次。


请使用浏览器的分享功能分享到微信等