You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle 19c中PL/SQL存储过程用JSON_OBJECT(*)加变量触发ORA-00904错误

Oracle 19c中JSON_OBJECT(*)结合PL/SQL变量的ORA-00904错误分析与解决

问题复现

1. 创建测试表并插入数据

create table JSON_TABLE (
    ID      NUMBER,
    COLUMN1 VARCHAR(100),
    COLUMN2 VARCHAR(100),
    COLUMN3 VARCHAR(100)
);
/
create table JSON_RESAULT_TABLE (
    ID          NUMBER,
    J_OBJECT    VARCHAR2(4000)
);
/

INSERT INTO JSON_TABLE VALUES (1, 'Random text 1', 'Value 1', 'Example data 1');
INSERT INTO JSON_TABLE VALUES (2, 'Random text 2', 'Value 2', 'Example data 2');
INSERT INTO JSON_TABLE VALUES (1, 'Random text 3', 'Value 3', 'Example data 3');
INSERT INTO JSON_TABLE VALUES (2, 'Random text 4', 'Value 4', 'Example data 4');
INSERT INTO JSON_TABLE VALUES (1, 'Random text 5', 'Value 5', 'Example data 5');
INSERT INTO JSON_TABLE VALUES (2, 'Random text 6', 'Value 6', 'Example data 6');
INSERT INTO JSON_TABLE VALUES (1, 'Random text 7', 'Value 7', 'Example data 7');
INSERT INTO JSON_TABLE VALUES (2, 'Random text 8', 'Value 8', 'Example data 8');
INSERT INTO JSON_TABLE VALUES (1, 'Random text 9', 'Value 9', 'Example data 9');
INSERT INTO JSON_TABLE VALUES (2, 'Random text 10', 'Value 10', 'Example data 10');
/

2. 触发错误的存储过程

执行以下存储过程时抛出ORA-00904: "V_ID_2": invalid identifier错误:

create or replace procedure p_json_test (v_id_1 NUMBER, v_id_2 NUMBER) is
begin
    INSERT INTO     JSON_RESAULT_TABLE
    SELECT          ID, JSON_OBJECT(*)
    FROM            JSON_TABLE
    WHERE           ID IN (v_id_1, v_id_2);
end;
/
execute p_json_test(1, 2);

3. 正常运行的两种情况

  • 显式指定JSON_OBJECT列时存储过程正常:
create or replace procedure p_json_test (v_id_1 NUMBER, v_id_2 NUMBER) is
begin
    INSERT INTO     JSON_RESAULT_TABLE
    SELECT ID, 
           JSON_OBJECT(
               'COLUMN1' VALUE COLUMN1,
               'COLUMN2' VALUE COLUMN2,
               'COLUMN3' VALUE COLUMN3)
    FROM            JSON_TABLE
    WHERE           ID IN (v_id_1, v_id_2);
end;
/
  • WHERE子句硬编码ID时存储过程正常:
create or replace procedure p_json_test (v_id_1 NUMBER, v_id_2 NUMBER) is
begin
    INSERT INTO     JSON_RESAULT_TABLE
    SELECT          ID, JSON_OBJECT(*)
    FROM            JSON_TABLE
    WHERE           ID IN (1, 2);
end;
/

错误原因

这是Oracle 19c版本中JSON_OBJECT(*)的解析bug:当在PL/SQL静态SQL语句中同时使用JSON_OBJECT(*)和PL/SQL绑定变量时,SQL解析器会错误地将WHERE子句中的绑定变量(如v_id_2)识别为表的列名,试图将其纳入JSON_OBJECT(*)要序列化的列列表中,最终因该变量并非表列而抛出无效标识符错误。

解决方法

以下是无需逐个指定列名即可将整行转为JSON对象的可行方案:

方案1:使用ROWTOJSON + JSON_OBJECT_T

利用ROWTOJSON将整行转为JSON格式的CLOB,再通过JSON_OBJECT_T转换为字符串,避开JSON_OBJECT(*)的解析问题:

create or replace procedure p_json_test (v_id_1 NUMBER, v_id_2 NUMBER) is
begin
    INSERT INTO JSON_RESAULT_TABLE
    SELECT ID, JSON_OBJECT_T(ROWTOJSON(jt)).to_string()
    FROM JSON_TABLE jt
    WHERE ID IN (v_id_1, v_id_2);
end;
/
execute p_json_test(1, 2);

方案2:使用动态SQL

通过动态SQL拼接查询语句,动态SQL的解析逻辑不会将绑定变量误判为表列:

create or replace procedure p_json_test (v_id_1 NUMBER, v_id_2 NUMBER) is
    v_sql varchar2(1000);
begin
    v_sql := 'INSERT INTO JSON_RESAULT_TABLE
              SELECT ID, JSON_OBJECT(*)
              FROM JSON_TABLE
              WHERE ID IN (:1, :2)';
    execute immediate v_sql using v_id_1, v_id_2;
end;
/
execute p_json_test(1, 2);

注意:动态SQL需注意防范SQL注入风险,此处使用绑定变量已规避该问题。

方案3:升级Oracle版本

该bug在Oracle 21c及更高版本中已被官方修复,若条件允许可升级数据库版本彻底解决问题。


内容的提问来源于stack exchange,提问作者Kamil Raszkowski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 22:02:13