KingbaseES与Oracle兼容性深度解析:数据类型、内置函数、PL/SQL全面对比

前言

做过数据库迁移的同学都知道,从Oracle迁到别的库,最怕的就是"语法不兼容、函数不支持、存储过程得重写"这老三样。KingbaseES在Oracle兼容这件事上下了不少功夫,28种数据类型、200+内置函数、21个PL/SQL内置包全给拿下了。今天咱们就掰开了揉碎了,从数据类型、内置函数、PL/SQL三个维度,把两者的兼容情况彻底说清楚。

文章目录

  • 前言
    • 一、先看全局:兼容能力到底覆盖了多广
    • 二、数据类型:28种全覆盖,零改动迁移
      • [2.1 字符类型:VARCHAR2、NVARCHAR2都能接](#2.1 字符类型:VARCHAR2、NVARCHAR2都能接)
      • [2.2 数值类型:从INT到BINARY_DOUBLE全覆盖](#2.2 数值类型:从INT到BINARY_DOUBLE全覆盖)
      • [2.3 日期时间类型:6种时间类型一个不落](#2.3 日期时间类型:6种时间类型一个不落)
      • [2.4 大对象与特殊类型:BLOB、CLOB、ROWID都能接](#2.4 大对象与特殊类型:BLOB、CLOB、ROWID都能接)
      • [2.5 半结构化类型:JSON和XML也不在话下](#2.5 半结构化类型:JSON和XML也不在话下)
    • 三、内置函数:200+函数逐类对比
      • [3.1 数字函数:26个,全部兼容](#3.1 数字函数:26个,全部兼容)
      • [3.2 字符函数:19个全部兼容,正则也能用](#3.2 字符函数:19个全部兼容,正则也能用)
      • [3.3 日期时间函数:22个全覆盖](#3.3 日期时间函数:22个全覆盖)
      • [3.4 转换函数:34个类型互转全部支持](#3.4 转换函数:34个类型互转全部支持)
      • [3.5 聚集函数:30个,包含高级统计](#3.5 聚集函数:30个,包含高级统计)
      • [3.6 分析函数:31个窗口函数全部支持](#3.6 分析函数:31个窗口函数全部支持)
      • [3.7 JSON和XML函数:34个半结构化处理函数](#3.7 JSON和XML函数:34个半结构化处理函数)
      • [3.8 差异速查表:哪些函数有坑](#3.8 差异速查表:哪些函数有坑)
    • 四、PL/SQL兼容性:迁移中最硬的骨头
      • [4.1 数据类型:标量、RECORD、集合全支持](#4.1 数据类型:标量、RECORD、集合全支持)
      • [4.2 控制语句:IF、CASE、三种LOOP全支持](#4.2 控制语句:IF、CASE、三种LOOP全支持)
      • [4.3 存储过程与函数:IN/OUT/IN OUT参数、重载、递归都支持](#4.3 存储过程与函数:IN/OUT/IN OUT参数、重载、递归都支持)
      • [4.4 游标:隐式、显式、REF CURSOR三种都支持](#4.4 游标:隐式、显式、REF CURSOR三种都支持)
      • [4.5 动态SQL:EXECUTE IMMEDIATE和DBMS_SQL两种方式](#4.5 动态SQL:EXECUTE IMMEDIATE和DBMS_SQL两种方式)
      • [4.6 触发器:行级、语句级、INSTEAD OF全覆盖](#4.6 触发器:行级、语句级、INSTEAD OF全覆盖)
      • [4.7 包(Package):自定义包+21个内置包](#4.7 包(Package):自定义包+21个内置包)
      • [4.8 异常处理:预定义、自定义、传播、捕获全支持](#4.8 异常处理:预定义、自定义、传播、捕获全支持)
    • 五、SQL语法兼容性:伪列、MERGE、DBLink都支持
      • [5.1 伪列:ROWNUM、ROWID、SEQUENCE、层次查询](#5.1 伪列:ROWNUM、ROWID、SEQUENCE、层次查询)
      • [5.2 高级SQL操作](#5.2 高级SQL操作)
    • 六、系统视图兼容性:70+视图,运维习惯不用改
      • [6.1 静态数据字典视图](#6.1 静态数据字典视图)
      • [6.2 动态性能视图](#6.2 动态性能视图)
    • 七、实操:Oracle到KingbaseES的迁移步骤
      • [7.1 导出导入的实操命令](#7.1 导出导入的实操命令)
      • [7.2 导入后的验证脚本](#7.2 导入后的验证脚本)
    • 八、写在最后

一、先看全局:兼容能力到底覆盖了多广

很多同学第一反应是:"兼容是不是就是支持个SELECT、INSERT?"真不是。KingbaseES走的是内核级别的兼容路线------不是说在外面套一层翻译壳子,而是在数据库引擎内部就把Oracle的那套语法、类型、函数体系给实现了。

目前Oracle常用能力的兼容率做到了100%,不光是基本的SQL语法和数据类型,连PL/SQL内置包、DBLink跨库访问、物化视图、分区操作这些高级特性也都支持。

下面这张图可以直观地看到兼容的全貌:

复制代码
┌──────────────────────────────────────────────────────────────┐
│                 Oracle 兼容能力全景图                          │
├──────────────┬──────────────┬──────────────┬────────────────┤
│  基础能力层   │  高级能力层   │   工具链层    │    接口层       │
├──────────────┼──────────────┼──────────────┼────────────────┤
│ SQL语法       │ ROWID        │ sys_dump     │ JDBC           │
│ 28种数据类型   │ BFILE        │ sys_restore  │ ODBC           │
│ 200+内置函数   │ DBLink       │ exp/imp      │ OCI            │
│ 70+系统视图    │ 物化视图      │ sys_bulkload │ OCCI           │
│ 完整PL/SQL    │ 分区操作      │ ksql         │ Pro*C          │
│ 伪列/表达式   │ 21个内置包    │              │ DCI            │
│ 条件/常量      │ XML/JSON     │              │                │
└──────────────┴──────────────┴──────────────┴────────────────┘

来,直接上硬数据:

兼容维度 子项数量 兼容状态
数据类型 28种 全部兼容
数字函数 26个 全部兼容
字符函数 19个 全部兼容
日期时间函数 22个 全部兼容
转换函数 34个 全部兼容
聚集函数 30个 全部兼容
分析函数 31个 全部兼容
XML函数 24个 全部兼容
JSON函数 10个 全部兼容
PL/SQL特性 9大类 全部支持
内置包 21个 全部支持
系统视图 70+ 全部兼容

光看表格可能还不够直观,下面咱们一个维度一个维度地展开,配上代码,看完你就知道迁移的时候该注意什么了。


二、数据类型:28种全覆盖,零改动迁移

数据类型是迁移的第一关------如果连字段类型都对不上,后面的代码全白搭。好消息是,Oracle的28种数据类型在KingbaseES里全部都能直接用,建表语句从Oracle搬到KingbaseES,一行都不用改

2.1 字符类型:VARCHAR2、NVARCHAR2都能接

字符类型是最常用的,Oracle有CHAR、VARCHAR2、NCHAR、NVARCHAR2、LONG这几位老熟人。KingbaseES对它们的支持是完整的,行为也一致。

sql 复制代码
-- 这段建表语句,在Oracle和KingbaseES上跑出来的结果一模一样
CREATE TABLE employees (
    emp_id      NUMBER(10),
    emp_name    VARCHAR2(100),
    emp_code    CHAR(10),
    region_name NVARCHAR2(50),
    memo        NCHAR(200)
);

来看完整的兼容情况:

Oracle类型 兼容状态 说明
CHAR 兼容 定长字符,最大2000字节
VARCHAR2 兼容 变长字符,最大32767字节
NCHAR 兼容 Unicode定长字符
NVARCHAR2 兼容 Unicode变长字符
LONG 兼容 兼容旧版LONG类型

2.2 数值类型:从INT到BINARY_DOUBLE全覆盖

数值类型这块同样没问题,NUMBER、FLOAT、BINARY_FLOAT、BINARY_DOUBLE、INT、SMALLINT全都支持。

sql 复制代码
-- 在PL/SQL块中使用各种数值类型,行为与Oracle一致
DECLARE
    v_int       INT := 100;
    v_num       NUMBER(10,2) := 12345.67;
    v_float     FLOAT := 3.14;
    v_binary_f  BINARY_FLOAT := 2.5f;
    v_binary_d  BINARY_DOUBLE := 3.14159d;
BEGIN
    DBMS_OUTPUT.PUT_LINE('INT: ' || v_int);
    DBMS_OUTPUT.PUT_LINE('NUMBER: ' || v_num);
    DBMS_OUTPUT.PUT_LINE('FLOAT: ' || v_float);
END;
/
Oracle类型 兼容状态 说明
NUMBER(p,s) 兼容 精确数值,最大精度38位
FLOAT 兼容 浮点数
BINARY_FLOAT 兼容 32位单精度浮点
BINARY_DOUBLE 兼容 64位双精度浮点
INT / INTEGER 兼容 整数类型
SMALLINT 兼容 小整数类型

2.3 日期时间类型:6种时间类型一个不落

日期时间类型对业务系统特别关键------订单时间、发货时间、账期计算,哪个都马虎不得。Oracle的6种日期时间类型,KingbaseES全部兼容。

sql 复制代码
-- 一张表把Oracle所有日期时间类型都涵盖进来
CREATE TABLE order_events (
    order_id      NUMBER(10),
    order_date    DATE,                            -- 精确到秒
    created_at    TIMESTAMP,                       -- 带微秒
    shipped_at    TIMESTAMP WITH TIME ZONE,        -- 带时区
    local_time    TIMESTAMP WITH LOCAL TIME ZONE,  -- 本地时区
    warranty      INTERVAL YEAR TO MONTH,          -- 年月间隔
    delivery_time INTERVAL DAY TO SECOND           -- 天秒间隔
);

-- 直接插入数据,语法跟Oracle一模一样
INSERT INTO order_events VALUES (
    1001,
    DATE '2025-03-15',
    TIMESTAMP '2025-03-15 10:30:00.123456',
    TIMESTAMP '2025-03-15 10:30:00 +08:00',
    TIMESTAMP '2025-03-15 10:30:00',
    INTERVAL '2-6' YEAR TO MONTH,
    INTERVAL '5 12:30:00' DAY TO SECOND
);
Oracle类型 兼容状态 说明
DATE 兼容 日期+时间(精确到秒)
TIMESTAMP 兼容 带微秒的时间戳
TIMESTAMP WITH TIME ZONE 兼容 带时区的时间戳
TIMESTAMP WITH LOCAL TIME ZONE 兼容 本地时区时间戳
INTERVAL YEAR TO MONTH 兼容 年月间隔
INTERVAL DAY TO SECOND 兼容 天秒间隔

2.4 大对象与特殊类型:BLOB、CLOB、ROWID都能接

LOB类型和特殊类型在复杂业务里用得很多。BLOB存文件、CLOB存长文本、BFILE引用外部文件、ROWID标识行------这些在KingbaseES里全部支持。

sql 复制代码
CREATE TABLE media_assets (
    asset_id    NUMBER(10) PRIMARY KEY,
    doc_content CLOB,              -- 大文本
    file_data   BLOB,              -- 二进制大对象
    unicode_doc NCLOB,             -- Unicode大文本
    raw_data    RAW(500),          -- 原始二进制
    file_ptr    BFILE,             -- 外部文件引用
    row_id      ROWID,             -- 物理行标识符
    urow_id     UROWID             -- 通用行标识符
);
Oracle类型 兼容状态 说明
BLOB 兼容 二进制大对象,最大1GB
CLOB 兼容 字符大对象
NCLOB 兼容 Unicode字符大对象
BFILE 兼容 外部二进制文件引用
RAW 兼容 原始二进制数据
LONG RAW 兼容 旧版二进制类型
ROWID 兼容 物理行标识符
UROWID 兼容 通用行标识符

2.5 半结构化类型:JSON和XML也不在话下

现在的系统,不处理点JSON和XML数据都不好意思出门。KingbaseES对Oracle的JSON和XML类型也做到了完整兼容。

sql 复制代码
-- JSON类型:建表、插入、查询一条龙
CREATE TABLE json_data (
    id      NUMBER PRIMARY KEY,
    info    JSON,
    payload JSONB
);

INSERT INTO json_data VALUES (
    1,
    '{"name": "张三", "age": 30, "skills": ["Java", "SQL"]}',
    '{"verified": true}'
);

-- 用JSON_VALUE提取字段,跟Oracle写法完全一致
SELECT JSON_VALUE(info, '$.name') AS name FROM json_data;

-- XML类型也一样
CREATE TABLE xml_docs (
    id      NUMBER PRIMARY KEY,
    content XMLType
);

INSERT INTO xml_docs VALUES (
    1,
    XMLType('<book><title>数据库迁移指南</title><author>技术团队</author></book>')
);

三、内置函数:200+函数逐类对比

函数兼容性直接决定了你的SQL要不要改。KingbaseES兼容了Oracle 200+个内置函数,涵盖数字、字符、日期、转换、聚合、分析、JSON、XML八大类。咱们一类一类来看。

3.1 数字函数:26个,全部兼容

数字函数是最基础的一类。ABS取绝对值、CEIL向上取整、ROUND四舍五入......这26个函数在KingbaseES里的行为跟Oracle完全一致。

sql 复制代码
-- 这段代码在Oracle和KingbaseES上跑出来的结果一模一样
SELECT
    ABS(-15)            AS abs_val,       -- 15
    CEIL(4.3)           AS ceil_val,      -- 5
    FLOOR(4.7)          AS floor_val,     -- 4
    ROUND(3.1415, 2)    AS round_val,     -- 3.14
    TRUNC(3.1415, 2)    AS trunc_val,     -- 3.14
    MOD(10, 3)          AS mod_val,       -- 1
    POWER(2, 10)        AS power_val,     -- 1024
    SQRT(144)           AS sqrt_val,      -- 12
    SIGN(-5)            AS sign_val,      -- -1
    LN(100)             AS ln_val,        -- 4.605...
    LOG(10, 100)        AS log_val        -- 2
FROM dual;

这里提一句:KingbaseES支持Oracle的dual虚拟表。你的SQL里要是用了FROM dual,直接搬过来就行,不用改。

3.2 字符函数:19个全部兼容,正则也能用

字符处理函数在业务代码里出现频率极高------截取、拼接、查找、替换,一个都不能少。

sql 复制代码
-- 日常字符串操作
SELECT
    UPPER('hello world')                    AS upper_str,    -- HELLO WORLD
    LOWER('HELLO WORLD')                    AS lower_str,    -- hello world
    INITCAP('hello world')                  AS initcap_str,  -- Hello World
    SUBSTR('KingbaseES', 1, 4)              AS substr_val,   -- King
    INSTR('KingbaseES', 'base')             AS instr_val,    -- 5
    LPAD('123', 10, '0')                    AS lpad_val,     -- 0000000123
    RPAD('abc', 10, '*')                    AS rpad_val,     -- abc*******
    TRIM('  hello  ')                       AS trim_val,     -- hello
    REPLACE('Jelly', 'J', 'K')              AS replace_val,  -- Kelly
    CONCAT('Hello', ' World')               AS concat_val    -- Hello World
FROM dual;

-- 正则表达式函数也完全兼容
SELECT
    REGEXP_SUBSTR('abc123def456', '[0-9]+')              AS first_num,
    REGEXP_REPLACE('Hello 123 World 456', '[0-9]', 'X') AS replaced
FROM dual;

有个小坑要注意CHR函数,Oracle允许传0,KingbaseES不行。如果你代码里用了CHR(0),迁移的时候得单独处理。

3.3 日期时间函数:22个全覆盖

日期函数是业务系统里用得最勤的------算账期、排班次、统计月报,全靠它们。

sql 复制代码
-- 常用日期函数一览
SELECT
    SYSDATE                                    AS now,
    CURRENT_DATE                               AS cur_date,
    ADD_MONTHS(DATE '2025-01-15', 3)           AS after_3m,    -- 3个月后的日期
    LAST_DAY(DATE '2025-02-10')                AS feb_last,    -- 该月最后一天
    NEXT_DAY(DATE '2025-03-15', 'MONDAY')      AS next_mon,    -- 下一个周一
    MONTHS_BETWEEN(DATE '2025-06-15', DATE '2025-01-15') AS months_diff,
    TRUNC(SYSDATE, 'MONTH')                    AS month_start, -- 月初
    ROUND(SYSDATE, 'DAY')                      AS rounded_day  -- 四舍五入到最近周日
FROM dual;

-- 格式化输出也完全兼容Oracle的写法
SELECT
    TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS')  AS formatted_date,
    TO_CHAR(SYSDATE, 'YYYY"年"MM"月"DD"日"')    AS cn_date
FROM dual;

注意CURRENT_TIMESTAMP在精度上可能和Oracle有细微差异。如果业务对时间戳精度敏感,建议显式指定精度参数,比如CURRENT_TIMESTAMP(6)

3.4 转换函数:34个类型互转全部支持

从字符串转数字、从数字转日期、从RAW转十六进制......Oracle的34个转换函数,KingbaseES全都兼容。

sql 复制代码
-- 常用转换函数示例
SELECT
    TO_NUMBER('123.45')                        AS num_val,
    TO_DATE('2025-03-15', 'YYYY-MM-DD')        AS date_val,
    TO_TIMESTAMP('2025-03-15 10:30:00',
                 'YYYY-MM-DD HH24:MI:SS')      AS ts_val,
    TO_CHAR(12345.67, '999,999.99')            AS formatted_num,
    TO_CHAR(DATE '2025-03-15', 'YYYY-MM-DD')   AS date_str,
    CAST('123' AS NUMBER)                      AS cast_val
FROM dual;

-- NULL处理函数(迁移中最常用的一组)
SELECT
    NVL(NULL, 'default')                       AS nvl_val,      -- default
    NVL2('value', 'yes', 'no')                 AS nvl2_val,     -- yes
    COALESCE(NULL, NULL, 'third')              AS coal_val,     -- third
    NULLIF('same', 'same')                     AS nullif_val,   -- NULL
    DECODE(1, 1, '一', 2, '二', '其他')         AS decode_val    -- 一
FROM dual;

实际做迁移的时候,NVLDECODE是用得最多的两个------很多老Oracle项目的SQL里到处都是。好消息是这两个函数行为完全一致,直接搬就行。

3.5 聚集函数:30个,包含高级统计

sql 复制代码
-- 基础聚合:日常统计报表离不开这些
SELECT
    department_id,
    COUNT(*)                 AS emp_count,
    AVG(salary)              AS avg_salary,
    SUM(salary)              AS total_salary,
    MAX(salary)              AS max_salary,
    MIN(salary)              AS min_salary,
    STDDEV(salary)           AS salary_stddev,
    VARIANCE(salary)         AS salary_var
FROM employees
GROUP BY department_id;

-- LISTAGG:把多行拼成一条字符串,做报表特别好用
SELECT
    department_id,
    LISTAGG(last_name, ', ') WITHIN GROUP (ORDER BY hire_date) AS name_list
FROM employees
GROUP BY department_id;

3.6 分析函数:31个窗口函数全部支持

分析函数(也叫窗口函数)是OLAP场景的杀手锏。ROW_NUMBER排名、LAG/LEAD取前后行、SUM累加------这31个函数在KingbaseES里全部兼容。

sql 复制代码
-- 三种排名函数的区别一目了然
SELECT
    emp_name,
    department_id,
    salary,
    ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS row_num,
    RANK()       OVER (PARTITION BY department_id ORDER BY salary DESC) AS rank_val,
    DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dense_rank_val
FROM employees;

-- LAG/LEAD:环比增长、同比对比就靠它们
SELECT
    order_date,
    amount,
    LAG(amount, 1)  OVER (ORDER BY order_date) AS prev_amount,
    LEAD(amount, 1) OVER (ORDER BY order_date) AS next_amount,
    amount - LAG(amount, 1) OVER (ORDER BY order_date) AS diff
FROM daily_sales;

-- 累计窗口:算累计工资、累计销售额
SELECT
    emp_name,
    department_id,
    salary,
    SUM(salary) OVER (
        PARTITION BY department_id
        ORDER BY hire_date
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS cumulative_salary
FROM employees;

3.7 JSON和XML函数:34个半结构化处理函数

现在越来越多的业务场景需要处理JSON和XML数据。KingbaseES兼容了Oracle全部10个JSON函数和24个XML函数。

sql 复制代码
-- JSON函数:构建、查询、提取
SELECT
    JSON_OBJECT('name' VALUE '张三', 'age' VALUE 30)    AS json_obj,
    JSON_ARRAY(1, 2, 3, 4, 5)                           AS json_arr,
    JSON_VALUE('{"a": 1, "b": 2}', '$.a')               AS json_val,
    JSON_QUERY('{"a": [1,2,3]}', '$.a')                  AS json_query;

-- XML函数:从关系数据生成XML
SELECT
    XMLELEMENT(NAME "emp",
        XMLFOREST(emp_name AS "name", salary AS "salary")
    ) AS xml_result
FROM employees
WHERE department_id = 10;

-- JSON_TABLE:把JSON数据展开成关系表来查
SELECT jt.*
FROM json_data,
     JSON_TABLE(info, '$'
         COLUMNS (
             name VARCHAR2(100) PATH '$.name',
             age  NUMBER PATH '$.age'
         )
     ) jt;

3.8 差异速查表:哪些函数有坑

虽然绝大多数函数是100%兼容的,但也有少数几个存在细微差异。做迁移的时候务必重点关注这几个

函数名 差异在哪 怎么处理
CHR KingbaseES不允许输入参数为0 检查业务是否用了CHR(0),有的话需要改写
CURRENT_TIMESTAMP 时间戳精度可能不同 显式指定精度参数,如CURRENT_TIMESTAMP(6)
CONVERT 第二、三个参数顺序跟Oracle反的 交换src_charset和dest_charset参数
NULLIF KingbaseES允许参数为NULL 这个差异通常是有利的,不用特殊处理
REGEXP_REPLACE match_param部分含义不同 涉及正则的场景务必逐条测试
REGEXP_COUNT 某些数据类型(如time)结果可能不同 有time类型参与正则的要重点测试
REGEXP_INSTR 同上 同上

这几个差异点不多,但每个都可能在实际项目中踩到。建议迁移的时候把涉及这几个函数的SQL单独拎出来测试。


四、PL/SQL兼容性:迁移中最硬的骨头

说到Oracle迁移,PL/SQL才是真正的重头戏。存储过程、函数、触发器、包------这些都是业务逻辑的载体,如果不能兼容,基本等于重写。KingbaseES在这块做得比较彻底,从数据类型到控制语句,从游标到动态SQL,从异常处理到内置包,全给兼容了。

4.1 数据类型:标量、RECORD、集合全支持

PL/SQL里的数据类型比SQL层更丰富------除了基本的NUMBER、VARCHAR2,还有PLS_INTEGER、RECORD记录类型、嵌套表、关联数组、VARRAY集合类型。KingbaseES全部支持。

sql 复制代码
DECLARE
    -- 基本标量类型
    v_count    PLS_INTEGER := 0;
    v_idx      BINARY_INTEGER := 1;
    v_name     VARCHAR2(100) := 'KingbaseES';

    -- SUBTYPE:基于已有类型定义子类型
    SUBTYPE t_salary IS NUMBER(10, 2);
    v_salary   t_salary := 15000.50;

    -- RECORD:自定义记录类型
    TYPE emp_record IS RECORD (
        emp_id   NUMBER(10),
        emp_name VARCHAR2(100),
        salary   NUMBER(10, 2)
    );
    v_emp emp_record;

    -- 嵌套表(NESTED TABLE)
    TYPE num_list IS TABLE OF NUMBER;
    v_numbers num_list := num_list(10, 20, 30, 40, 50);

    -- 关联数组(INDEX BY)
    TYPE name_map IS TABLE OF VARCHAR2(100) INDEX BY PLS_INTEGER;
    v_names name_map;

    -- VARRAY(变长数组)
    TYPE int_array IS VARRAY(10) OF INTEGER;
    v_arr int_array := int_array(1, 2, 3);
BEGIN
    v_names(1) := 'Alice';
    v_names(2) := 'Bob';
    v_names(3) := 'Charlie';

    DBMS_OUTPUT.PUT_LINE('Count: ' || v_numbers.COUNT);
    DBMS_OUTPUT.PUT_LINE('First: ' || v_numbers.FIRST);
    DBMS_OUTPUT.PUT_LINE('Last: ' || v_numbers.LAST);
END;
/

4.2 控制语句:IF、CASE、三种LOOP全支持

控制语句是PL/SQL的骨架。IF条件判断、CASE分支选择、三种LOOP循环------KingbaseES全部兼容,写法跟Oracle完全一致。

sql 复制代码
DECLARE
    v_score NUMBER := 85;
    v_grade VARCHAR2(2);
BEGIN
    -- IF条件控制
    IF v_score >= 90 THEN
        v_grade := 'A';
    ELSIF v_score >= 80 THEN
        v_grade := 'B';
    ELSIF v_score >= 70 THEN
        v_grade := 'C';
    ELSE
        v_grade := 'D';
    END IF;

    -- CASE表达式(更简洁的写法)
    v_grade := CASE
        WHEN v_score >= 90 THEN 'A'
        WHEN v_score >= 80 THEN 'B'
        WHEN v_score >= 70 THEN 'C'
        ELSE 'D'
    END;

    -- 三种循环方式

    -- 1. 基本LOOP + EXIT WHEN
    DECLARE i NUMBER := 0; BEGIN
        LOOP
            i := i + 1;
            EXIT WHEN i > 5;
        END LOOP;
    END;

    -- 2. FOR LOOP(最常用)
    FOR j IN 1..5 LOOP
        DBMS_OUTPUT.PUT_LINE('j = ' || j);
    END LOOP;

    -- 3. WHILE LOOP
    DECLARE k NUMBER := 1; BEGIN
        WHILE k <= 5 LOOP
            k := k + 1;
        END LOOP;
    END;
END;
/

4.3 存储过程与函数:IN/OUT/IN OUT参数、重载、递归都支持

存储过程和函数是业务逻辑的核心载体。KingbaseES支持三种参数模式(IN、OUT、IN OUT),支持过程重载和递归调用,参数个数上限达到65536个。

sql 复制代码
-- 创建存储过程:转账场景,带OUT参数返回状态
CREATE OR REPLACE PROCEDURE transfer_funds(
    p_from_id   IN  NUMBER,
    p_to_id     IN  NUMBER,
    p_amount    IN  NUMBER,
    p_status    OUT VARCHAR2
) AS
    v_balance NUMBER;
BEGIN
    -- 先查余额
    SELECT balance INTO v_balance
    FROM accounts WHERE account_id = p_from_id;

    IF v_balance < p_amount THEN
        p_status := 'INSUFFICIENT_FUNDS';
        RETURN;
    END IF;

    -- 扣款和入账
    UPDATE accounts SET balance = balance - p_amount
    WHERE account_id = p_from_id;

    UPDATE accounts SET balance = balance + p_amount
    WHERE account_id = p_to_id;

    COMMIT;
    p_status := 'SUCCESS';
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        p_status := 'ERROR: ' || SQLERRM;
END transfer_funds;
/

-- 创建函数:计算奖金,带异常处理
CREATE OR REPLACE FUNCTION calc_bonus(
    p_salary    NUMBER,
    p_dept_id   NUMBER
) RETURN NUMBER AS
    v_rate NUMBER;
BEGIN
    SELECT bonus_rate INTO v_rate
    FROM dept_bonus WHERE dept_id = p_dept_id;

    RETURN p_salary * v_rate;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        RETURN p_salary * 0.1;  -- 没配置奖金比例就默认10%
END calc_bonus;
/

-- 调用存储过程
DECLARE
    v_status VARCHAR2(100);
BEGIN
    transfer_funds(1001, 1002, 5000, v_status);
    DBMS_OUTPUT.PUT_LINE('转账结果: ' || v_status);
END;
/

4.4 游标:隐式、显式、REF CURSOR三种都支持

游标在PL/SQL里用得太多了------遍历数据、逐行处理、返回结果集。KingbaseES完整支持Oracle的三种游标模式。

sql 复制代码
DECLARE
    -- 显式游标
    CURSOR emp_cur IS
        SELECT emp_name, salary FROM employees WHERE department_id = 10;

    -- 带参数的游标
    CURSOR dept_emp_cur(p_dept_id NUMBER) IS
        SELECT emp_name, salary FROM employees WHERE department_id = p_dept_id;

    -- REF CURSOR(游标变量,最灵活的方式)
    TYPE ref_cursor IS REF CURSOR;
    v_ref_cur ref_cursor;
    v_name    VARCHAR2(100);
    v_sal     NUMBER;
BEGIN
    -- 方式一:FOR循环遍历显式游标(最简洁)
    FOR emp_rec IN emp_cur LOOP
        DBMS_OUTPUT.PUT_LINE(emp_rec.emp_name || ': ' || emp_rec.salary);
    END LOOP;

    -- 方式二:OPEN/FETCH/CLOSE(手动控制,更灵活)
    OPEN dept_emp_cur(20);
    LOOP
        FETCH dept_emp_cur INTO v_name, v_sal;
        EXIT WHEN dept_emp_cur%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(v_name || ': ' || v_sal);
    END LOOP;
    CLOSE dept_emp_cur;

    -- 方式三:REF CURSOR(动态绑定SQL)
    OPEN v_ref_cur FOR SELECT emp_name, salary FROM employees WHERE salary > 10000;
    LOOP
        FETCH v_ref_cur INTO v_name, v_sal;
        EXIT WHEN v_ref_cur%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(v_name || ': ' || v_sal);
    END LOOP;
    CLOSE v_ref_cur;

    -- 隐式游标属性:拿影响行数
    UPDATE employees SET salary = salary * 1.1 WHERE department_id = 10;
    DBMS_OUTPUT.PUT_LINE('更新了 ' || SQL%ROWCOUNT || ' 行');
END;
/

4.5 动态SQL:EXECUTE IMMEDIATE和DBMS_SQL两种方式

动态SQL在业务里用得很多------表名是运行时决定的、SQL语句是拼接出来的、返回列不确定的。Oracle提供了两种方式来处理,KingbaseES都支持。

方式一:EXECUTE IMMEDIATE(大多数场景够用)

sql 复制代码
DECLARE
    v_table_name VARCHAR2(100) := 'employees';
    v_count      NUMBER;
    v_sql        VARCHAR2(4000);
BEGIN
    -- 动态查询
    v_sql := 'SELECT COUNT(*) FROM ' || v_table_name;
    EXECUTE IMMEDIATE v_sql INTO v_count;
    DBMS_OUTPUT.PUT_LINE('总行数: ' || v_count);

    -- 动态DDL
    EXECUTE IMMEDIATE 'CREATE TABLE temp_log (id NUMBER, msg VARCHAR2(200))';

    -- 带绑定变量的DML(防SQL注入,推荐写法)
    v_sql := 'UPDATE employees SET salary = salary * :factor WHERE department_id = :dept';
    EXECUTE IMMEDIATE v_sql USING 1.15, 10;

    -- 带RETURNING子句的动态SQL
    DECLARE
        v_new_sal NUMBER;
    BEGIN
        EXECUTE IMMEDIATE
            'UPDATE employees SET salary = :sal WHERE emp_id = :id RETURNING salary INTO :ret'
            USING 20000, 1001
            RETURNING INTO v_new_sal;
        DBMS_OUTPUT.PUT_LINE('新工资: ' || v_new_sal);
    END;
END;
/

方式二:DBMS_SQL包(列数和类型在编译时不确定的场景)

sql 复制代码
DECLARE
    v_cursor   INTEGER;
    v_sql      VARCHAR2(4000) := 'SELECT emp_name, salary FROM employees WHERE department_id = :1';
    v_name     VARCHAR2(100);
    v_sal      NUMBER;
BEGIN
    v_cursor := DBMS_SQL.OPEN_CURSOR;
    DBMS_SQL.PARSE(v_cursor, v_sql, DBMS_SQL.NATIVE);
    DBMS_SQL.BIND_VARIABLE(v_cursor, ':1', 10);
    DBMS_SQL.DEFINE_COLUMN(v_cursor, 1, v_name, 100);
    DBMS_SQL.DEFINE_COLUMN(v_cursor, 2, v_sal);
    DBMS_SQL.EXECUTE(v_cursor);

    LOOP
        EXIT WHEN DBMS_SQL.FETCH_ROWS(v_cursor) = 0;
        DBMS_SQL.COLUMN_VALUE(v_cursor, 1, v_name);
        DBMS_SQL.COLUMN_VALUE(v_cursor, 2, v_sal);
        DBMS_OUTPUT.PUT_LINE(v_name || ': ' || v_sal);
    END LOOP;

    DBMS_SQL.CLOSE_CURSOR(v_cursor);
END;
/

4.6 触发器:行级、语句级、INSTEAD OF全覆盖

触发器在Oracle项目里很常见------审计日志、数据校验、视图更新。KingbaseES支持行级和语句级两种粒度,BEFORE、AFTER、INSTEAD OF三种时机。

sql 复制代码
-- 行级BEFORE触发器:薪资变更审计
CREATE OR REPLACE TRIGGER trg_audit_salary
BEFORE UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
    IF :NEW.salary != :OLD.salary THEN
        INSERT INTO salary_audit(emp_id, old_sal, new_sal, change_time)
        VALUES(:NEW.emp_id, :OLD.salary, :NEW.salary, SYSDATE);
    END IF;
END;
/

-- 语句级AFTER触发器:批量操作后汇总
CREATE OR REPLACE TRIGGER trg_log_bulk_update
AFTER UPDATE ON employees
DECLARE
    v_count NUMBER;
BEGIN
    SELECT COUNT(*) INTO v_count FROM salary_audit
    WHERE change_time >= TRUNC(SYSDATE);
    DBMS_OUTPUT.PUT_LINE('今日变更记录数: ' || v_count);
END;
/

-- INSTEAD OF触发器:让只读视图也能UPDATE
CREATE OR REPLACE VIEW emp_dept_view AS
SELECT e.emp_id, e.emp_name, e.salary, d.dept_name
FROM employees e JOIN departments d ON e.department_id = d.dept_id;

CREATE OR REPLACE TRIGGER trg_emp_dept_view
INSTEAD OF UPDATE ON emp_dept_view
FOR EACH ROW
BEGIN
    UPDATE employees SET
        emp_name = :NEW.emp_name,
        salary   = :NEW.salary
    WHERE emp_id = :NEW.emp_id;
END;
/

-- 启用/禁用触发器
ALTER TRIGGER trg_audit_salary DISABLE;   -- 禁用
ALTER TRIGGER trg_audit_salary ENABLE;    -- 启用

4.7 包(Package):自定义包+21个内置包

包(Package)是Oracle PL/SQL最重要的组织单元------把相关的过程、函数、变量、类型封装到一起,对外提供清晰的接口。KingbaseES不仅支持自定义包,还内置了Oracle的21个常用包。

先来看一个完整的自定义包示例:

sql 复制代码
-- 包规范(Specification):定义对外接口
CREATE OR REPLACE PACKAGE pkg_emp_mgmt AS
    MAX_SALARY   CONSTANT NUMBER := 999999.99;
    DEFAULT_DEPT CONSTANT NUMBER := 10;
    TYPE emp_cursor IS REF CURSOR;
    g_total_employees NUMBER;

    PROCEDURE add_employee(
        p_name VARCHAR2, p_salary NUMBER, p_dept_id NUMBER
    );

    -- 支持函数重载:同名不同参
    FUNCTION get_emp_count RETURN NUMBER;
    FUNCTION get_emp_count(p_dept_id NUMBER) RETURN NUMBER;

    PROCEDURE get_employees(p_dept_id NUMBER, p_cur OUT emp_cursor);
END pkg_emp_mgmt;
/

-- 包体(Body):实现具体逻辑
CREATE OR REPLACE PACKAGE BODY pkg_emp_mgmt AS
    PROCEDURE add_employee(
        p_name VARCHAR2, p_salary NUMBER, p_dept_id NUMBER
    ) AS
    BEGIN
        IF p_salary > MAX_SALARY THEN
            RAISE_APPLICATION_ERROR(-20001, '薪资超出上限');
        END IF;
        INSERT INTO employees(emp_name, salary, department_id)
        VALUES(p_name, p_salary, p_dept_id);
        g_total_employees := g_total_employees + 1;
    END add_employee;

    FUNCTION get_emp_count RETURN NUMBER AS
        v_count NUMBER;
    BEGIN
        SELECT COUNT(*) INTO v_count FROM employees;
        RETURN v_count;
    END get_emp_count;

    FUNCTION get_emp_count(p_dept_id NUMBER) RETURN NUMBER AS
        v_count NUMBER;
    BEGIN
        SELECT COUNT(*) INTO v_count
        FROM employees WHERE department_id = p_dept_id;
        RETURN v_count;
    END get_emp_count;

    PROCEDURE get_employees(p_dept_id NUMBER, p_cur OUT emp_cursor) AS
    BEGIN
        OPEN p_cur FOR
            SELECT emp_name, salary FROM employees
            WHERE department_id = p_dept_id ORDER BY salary DESC;
    END get_employees;

BEGIN
    -- 包初始化块(首次调用时自动执行)
    SELECT COUNT(*) INTO g_total_employees FROM employees;
END pkg_emp_mgmt;
/

-- 调用包里的过程和函数
DECLARE
    v_count NUMBER;
    v_cur   pkg_emp_mgmt.emp_cursor;
    v_name  VARCHAR2(100);
    v_sal   NUMBER;
BEGIN
    pkg_emp_mgmt.add_employee('赵六', 12000, 20);

    v_count := pkg_emp_mgmt.get_emp_count;        -- 全部员工数
    DBMS_OUTPUT.PUT_LINE('总人数: ' || v_count);

    v_count := pkg_emp_mgmt.get_emp_count(20);    -- 20号部门人数
    DBMS_OUTPUT.PUT_LINE('部门人数: ' || v_count);

    pkg_emp_mgmt.get_employees(20, v_cur);
    LOOP
        FETCH v_cur INTO v_name, v_sal;
        EXIT WHEN v_cur%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(v_name || ': ' || v_sal);
    END LOOP;
    CLOSE v_cur;
END;
/

21个内置包一览:

包名 干什么用的 包名 干什么用的
DBMS_OUTPUT 控制台打印输出 DBMS_SQL 动态SQL处理
DBMS_LOB 大对象读写操作 DBMS_UTILITY 通用工具函数
DBMS_METADATA 导出对象DDL DBMS_XMLQUERY XML查询处理
DBMS_JOB 定时任务调度 UTL_HTTP 发HTTP请求
DBMS_SCHEDULER 高级任务调度 UTL_ENCODE 编码解码
DBMS_SESSION 会话管理 UTL_I18N 国际化处理
DBMS_RANDOM 随机数生成 UTL_RAW RAW数据处理
DBMS_DDL 动态DDL操作 OWA_UTIL Web应用工具
DBMS_MVIEW 物化视图管理 XMLTYPE XML类型操作
DBMS_OBFUSCATION_TOOLKIT 数据加密 DBMS_SQL_MONITOR SQL执行监控

4.8 异常处理:预定义、自定义、传播、捕获全支持

异常处理保证了程序的健壮性。KingbaseES完整支持Oracle的异常处理体系。

sql 复制代码
DECLARE
    v_salary NUMBER;
    -- 自定义异常
    e_invalid_salary EXCEPTION;
    PRAGMA EXCEPTION_INIT(e_invalid_salary, -20001);
BEGIN
    SELECT salary INTO v_salary FROM employees WHERE emp_id = 9999;

EXCEPTION
    -- Oracle预定义异常,直接捕获
    WHEN NO_DATA_FOUND THEN
        DBMS_OUTPUT.PUT_LINE('查无此人');

    WHEN TOO_MANY_ROWS THEN
        DBMS_OUTPUT.PUT_LINE('返回了多行数据');

    WHEN DUP_VAL_ON_INDEX THEN
        DBMS_OUTPUT.PUT_LINE('违反唯一约束');

    -- 自定义异常
    WHEN e_invalid_salary THEN
        DBMS_OUTPUT.PUT_LINE('薪资数据异常');

    -- 兜底处理
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('错误码: ' || SQLCODE);
        DBMS_OUTPUT.PUT_LINE('错误信息: ' || SQLERRM);
        RAISE;  -- 重新抛出,让上层处理
END;
/

五、SQL语法兼容性:伪列、MERGE、DBLink都支持

5.1 伪列:ROWNUM、ROWID、SEQUENCE、层次查询

Oracle的伪列用得很多,尤其是ROWNUM做分页、ROWID做快速定位、SEQUENCE生成序列号。KingbaseES对这四类伪列全部支持。

sql 复制代码
-- ROWNUM:限制返回行数(最常用的分页方式)
SELECT emp_name, salary
FROM employees
WHERE ROWNUM <= 10
ORDER BY salary DESC;

-- ROWID:拿到行的物理地址
SELECT ROWID, emp_name FROM employees WHERE emp_id = 1001;

-- 序列伪列
CREATE SEQUENCE seq_emp START WITH 1 INCREMENT BY 1;
SELECT seq_emp.NEXTVAL FROM dual;   -- 取下一个值
SELECT seq_emp.CURRVAL FROM dual;   -- 取当前值

-- 层次查询伪列:组织架构树
SELECT
    LEVEL,
    LPAD(' ', 2 * (LEVEL - 1)) || emp_name AS org_chart,
    CONNECT_BY_ISLEAF AS is_leaf
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR emp_id = manager_id;

5.2 高级SQL操作

除了基本CRUD,Oracle还有不少高级SQL操作,在迁移时经常碰到。KingbaseES对这些也都做了兼容:

sql 复制代码
-- MERGE:有则更新,无则插入(数据同步常用)
MERGE INTO target_table t
USING source_table s
ON (t.id = s.id)
WHEN MATCHED THEN
    UPDATE SET t.name = s.name, t.salary = s.salary
WHEN NOT MATCHED THEN
    INSERT (id, name, salary) VALUES (s.id, s.name, s.salary);

-- INSERT ALL:一条SELECT插入多张表
INSERT ALL
    INTO emp_archive (emp_id, emp_name, salary) VALUES (emp_id, emp_name, salary)
    INTO emp_audit   (emp_id, action, action_time) VALUES (emp_id, 'ARCHIVE', SYSDATE)
SELECT emp_id, emp_name, salary FROM employees WHERE status = 'INACTIVE';

-- INSERT RETURNING:插入后返回生成的ID
INSERT INTO employees(emp_name, salary)
VALUES ('新员工', 10000)
RETURNING emp_id INTO :new_id;

-- FLASHBACK查询:查看历史数据
SELECT * FROM employees AS OF TIMESTAMP (SYSDATE - INTERVAL '1' HOUR);

-- DBLink:跨库查询(支持同构和异构数据库)
SELECT * FROM employees@remote_oracle_db WHERE department_id = 10;

六、系统视图兼容性:70+视图,运维习惯不用改

Oracle DBA最熟悉的就是那一套数据字典视图------ALL_TABLES查表、DBA_USERS查用户、V S E S S I O N 查会话、 V SESSION查会话、V SESSION查会话、VLOCK查锁。KingbaseES把这些视图都兼容了,迁移后DBA可以继续用原来的运维习惯。

6.1 静态数据字典视图

sql 复制代码
-- 查表结构(日常最常用的一组查询)
SELECT * FROM ALL_TABLES WHERE OWNER = 'HR';
SELECT * FROM ALL_TAB_COLUMNS WHERE TABLE_NAME = 'EMPLOYEES';
SELECT * FROM ALL_INDEXES WHERE TABLE_NAME = 'EMPLOYEES';
SELECT * FROM ALL_CONSTRAINTS WHERE TABLE_NAME = 'EMPLOYEES';

-- 查代码和对象
SELECT * FROM ALL_SOURCE WHERE NAME = 'PKG_EMP_MGMT';
SELECT * FROM ALL_OBJECTS WHERE OBJECT_TYPE = 'PACKAGE';
SELECT * FROM ALL_TRIGGERS WHERE TABLE_NAME = 'EMPLOYEES';
SELECT * FROM ALL_VIEWS WHERE OWNER = 'HR';
SELECT * FROM ALL_SYNONYMS WHERE OWNER = 'HR';
SELECT * FROM ALL_SEQUENCES WHERE SEQUENCE_OWNER = 'HR';
SELECT * FROM ALL_DB_LINKS;
SELECT * FROM ALL_DIRECTORIES;
SELECT * FROM ALL_PART_TABLES WHERE OWNER = 'HR';

-- DBA级视图(需要更高权限)
SELECT * FROM DBA_USERS;
SELECT * FROM DBA_TABLESPACES;
SELECT * FROM DBA_FREE_SPACE;
SELECT * FROM DBA_ROLES;
SELECT * FROM DBA_ROLE_PRIVS WHERE GRANTEE = 'HR';

-- USER级视图(只看自己下的对象)
SELECT * FROM USER_TABLES;
SELECT * FROM USER_TAB_COMMENTS;
SELECT * FROM USER_CONSTRAINTS;
SELECT * FROM USER_SOURCE;

-- 回收站(删了还能找回来)
SELECT * FROM RECYCLEBIN;

6.2 动态性能视图

动态性能视图是排查问题的利器------看看谁在锁表、SQL执行多慢、系统负载多高。

sql 复制代码
-- 实例和数据库基本信息
SELECT * FROM V$DATABASE;
SELECT * FROM V$INSTANCE;

-- 会话监控:谁连上来了,在执行什么
SELECT * FROM V$SESSION WHERE USERNAME = 'HR';
SELECT * FROM V$CONTEXT;

-- 锁诊断:谁锁了谁
SELECT * FROM V$LOCK;
SELECT * FROM V$LOCKED_OBJECT;

-- 性能统计:TPS、QPS等指标
SELECT * FROM V$SYSSTAT;
SELECT * FROM V$METRIC;
SELECT * FROM V$SYSMETRIC;
SELECT * FROM V$SYSMETRIC_HISTORY;

七、实操:Oracle到KingbaseES的迁移步骤

前面说了这么多兼容性,最后来点实在的------具体怎么迁。这里给出一套经过验证的六步迁移流程:

复制代码
 ┌─────────────────────────────────────────────────────────────┐
 │                 迁移六步走                                    │
 ├─────────────────────────────────────────────────────────────┤
 │                                                             │
 │  第一步:评估                                                │
 │  ┌──────────────────────────────────────────────────────┐  │
 │  │ • 梳理Oracle版本和使用的特性清单                       │  │
 │  │ • 标记自定义类型、内置包、DBLink等高级特性             │  │
 │  │ • 估算数据量、并发量和存储需求                         │  │
 │  └──────────────────────────────────────────────────────┘  │
 │                         ↓                                   │
 │  第二步:Schema迁移                                          │
 │  ┌──────────────────────────────────────────────────────┐  │
 │  │ • 用exp/imp工具导出Oracle Schema                      │  │
 │  │ • 导入到KingbaseES(自动创建Oracle兼容模式)           │  │
 │  │ • 验证表结构、索引、约束、视图完整性                   │  │
 │  └──────────────────────────────────────────────────────┘  │
 │                         ↓                                   │
 │  第三步:PL/SQL迁移                                          │
 │  ┌──────────────────────────────────────────────────────┐  │
 │  │ • 存储过程、函数、包、触发器直接迁移                   │  │
 │  │ • 重点验证CHR(0)、CONVERT参数顺序、正则match_param    │  │
 │  │ • 测试DBMS_SQL、UTL_HTTP等内置包功能                  │  │
 │  └──────────────────────────────────────────────────────┘  │
 │                         ↓                                   │
 │  第四步:数据迁移                                            │
 │  ┌──────────────────────────────────────────────────────┐  │
 │  │ • 小数据量:exp/imp工具直接导                          │  │
 │  │ • 大数据量:用sys_bulkload高速加载                     │  │
 │  │ • 增量同步:配置逻辑复制                               │  │
 │  └──────────────────────────────────────────────────────┘  │
 │                         ↓                                   │
 │  第五步:应用适配                                            │
 │  ┌──────────────────────────────────────────────────────┐  │
 │  │ • JDBC/ODBC驱动替换,修改连接串                        │  │
 │  │ • OCI/OCCI/Pro*C接口适配                              │  │
 │  │ • 连接池参数调整                                       │  │
 │  └──────────────────────────────────────────────────────┘  │
 │                         ↓                                   │
 │  第六步:验证上线                                            │
 │  ┌──────────────────────────────────────────────────────┐  │
 │  │ • 功能测试:业务全流程回归                             │  │
 │  │ • 性能测试:跑基准对比,用Hints做调优                  │  │
 │  │ • 建议双写或灰度上线,降低风险                         │  │
 │  └──────────────────────────────────────────────────────┘  │
 └─────────────────────────────────────────────────────────────┘

7.1 导出导入的实操命令

Oracle端导出:

bash 复制代码
# 用exp工具导出整个Schema
exp userid=hr/password@orcl OWNER=hr FILE=hr_backup.dmp LOG=hr_export.log

KingbaseES端导入:

bash 复制代码
# 用imp工具导入,指定源用户和目标用户
imp userid=hr/password@kingbase FILE=hr_backup.dmp LOG=hr_import.log FROMUSER=hr TOUSER=hr

7.2 导入后的验证脚本

数据导入完了不能直接用,得先验证一下对象是否完整:

sql 复制代码
-- 1. 对比表数量
SELECT COUNT(*) AS table_count FROM USER_TABLES;

-- 2. 对比存储过程和函数
SELECT NAME, TYPE, STATUS FROM USER_SOURCE
GROUP BY NAME, TYPE, STATUS
ORDER BY TYPE, NAME;

-- 3. 对比索引
SELECT INDEX_NAME, TABLE_NAME, STATUS FROM USER_INDEXES;

-- 4. 编译状态检查(重点!有INVALID的要排查)
SELECT OBJECT_NAME, OBJECT_TYPE, STATUS
FROM USER_OBJECTS
WHERE OBJECT_TYPE IN ('PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY', 'TRIGGER', 'VIEW')
ORDER BY STATUS, OBJECT_TYPE;

-- 5. 约束检查
SELECT CONSTRAINT_NAME, TABLE_NAME, CONSTRAINT_TYPE, STATUS
FROM USER_CONSTRAINTS
ORDER BY TABLE_NAME;

八、写在最后

最后用一张汇总表收个尾:

维度 Oracle特性数量 兼容数量 兼容率
数据类型 28种 28种 100%
数字函数 26个 26个 100%
字符函数 19个 19个 100%
日期时间函数 22个 22个 100%
转换函数 34个 34个 100%
聚集函数 30个 30个 100%
分析函数 31个 31个 100%
JSON函数 10个 10个 100%
XML函数 24个 24个 100%
PL/SQL数据类型 4大类 4大类 100%
PL/SQL控制语句 3大类 3大类 100%
PL/SQL内置包 21个 21个 100%
静态数据字典视图 70+ 70+ 100%
动态性能视图 14个 14个 100%

总结三句话:

  1. 绝大多数Oracle SQL和PL/SQL代码可以直接在KingbaseES上跑,不需要改写。数据类型、函数、存储过程、包、触发器------这些都做到了内核级兼容。

  2. DBA的运维习惯可以平移 。ALL_TABLES、DBA_USERS、V S E S S I O N 、 V SESSION、V SESSION、VLOCK这些常用视图全都兼容,排查问题的套路不用变。

  3. 少数差异点要重点测试CHR(0)CONVERT参数顺序、正则表达式的match_param------这几个有细微差异,迁移时把它们涉及的SQL单独拎出来跑一遍就够了。

相关推荐
2301_808414381 小时前
MySQL数据类型
数据库·mysql
minji...1 小时前
Linux 线程同步与互斥(六) 线程安全与重入问题,死锁,线程done
linux·运维·开发语言·数据库·c++·算法·安全
小羽网安4 小时前
从零开始学习 sql 注入,常见的 sql 注入解析
数据库·sql·学习
2401_846339564 小时前
CSS如何优化大型项目样式_使用SASS预处理器提升开发效率
jvm·数据库·python
ss27311 小时前
食谱推荐系统功能测试如何写?
java·数据库·spring boot·功能测试
l1t11 小时前
DeepSeek总结的数据库外部表
数据库
m0_6742946411 小时前
如何编写SQL存储过程性能对比_记录执行时间评估优化效果
jvm·数据库·python
014-code11 小时前
CompletableFuture 实战模板(超时、组合、异常链处理)
java·数据库
运气好好的11 小时前
怎样开启phpMyAdmin的操作审计日志_记录每条执行的SQL
jvm·数据库·python