我需要在Oracle 12c v12.1.0.2中把JSON转换成数据表(键值列)。
例如,有一个JSON字符串,如
{"ID": 10, "Description": "TestJSON", "status":"New"}
我需要将其转换为.NET语言。
Column1 Column2
------------------------------------
ID 10
Description TestJSON
status New
现在,我的JSON字符串可以改变属性的数量,因此我需要保持动态的转换。
我试着使用execute immediate :
set serveroutput on;
declare
sqlsmt VARCHAR2(200);
t3 varchar2(50);
begin
sqlsmt := 'SELECT * '||
'FROM json_table( ( select jsonstr from mytable where ID= 10) , ''$[*]'' '||
'COLUMNS ( :t1 PATH ''$.''|| '':t2'' ))';
execute immediate sqlsmt into t3 using 'desc' , '$.Description' ;
DBMS_OUTPUT.PUT_LINE( 'Output Variable: ' || t3);
END;
然而,我得到以下错误。
ORA-00904: : invalid identifier
ORA-06512: at line 8
00904. 00000 - "%s: invalid identifier"
请帮助我。我使用的是Oracle 12c V1。但我真的需要从JSON中动态提取列。
有几件事可以帮助动态SQL(假设你真的需要使用它)。第一个是使用 dbms_output
来显示生成的语句,然后再尝试执行它;所以在你的案例中。
...
dbms_output.put_line(sqlsmt);
execute immediate sqlsmt into t3;
--using 'descr' , '$.Description' ;
DBMS_OUTPUT.PUT_LINE( 'Output Variable: ' || t3);
END;
/
与你的代码显示。
SELECT * FROM json_table( ( select jsonstr from mytable where ID= 10) , '$[*]' COLUMNS ( :t1 PATH '$.'|| ':t2' ))
最明显的问题是 '$.'|| ':t2'
,其中 :t2
不应该用引号,这不会导致错误,但会阻止它被绑定到你的变量上,因为它是一个文字值。你也有 $.
部分在该位和你的变量值中,但又没有到那个程度。
与所有的动态SQL一样,你只能为变量提供在 using
子句。你试图将列名作为绑定变量来传递,这是不允许的;所以它试图用 :t1
作为输出列名,而不是 desc
;和 :t1
不是一个有效的名字。(也不是 desc
因为那是一个保留字--但无论哪一个都会得到同样的错误)。) 所以,你必须将列名连接起来,而不是绑定它。
看起来你可以使用 :t2
但是你也不能这样做,不是作为一个动态的SQL限制,而是作为一个SQLJSON限制--如果你走到那一步,用一个有效的变量值,你仍然会得到 "ORA-40454: path expression not a literal"。你也必须将路径连入语句中。
最后是 $[*]
不允许你匹配 Description
...这就引出了关于动态SQL的第二个提示;先让静态查询正常工作,然后再使其动态化。
所以把这些放在一起,你可以这样做:
declare
sqlsmt varchar2(200);
t1 varchar2(30) := 'descr';
t2 varchar2(30) := 'Description';
t3 varchar2(50);
begin
sqlsmt := 'SELECT * '||
'FROM json_table( ( select jsonstr from mytable where ID= 10) , ''$'' '||
'COLUMNS ( ' || t1 || ' PATH ''$.' || t2 || '''))';
dbms_output.put_line(sqlsmt);
execute immediate sqlsmt into t3;
dbms_output.put_line( 'Output Variable: ' || t3);
end;
/
用你的示例数据输出。
SELECT * FROM json_table( ( select jsonstr from mytable where ID= 10) , '$' COLUMNS ( descr PATH '$.Description'))
Output Variable: TestJSON
这是一个有点奇怪的事情,唯一的东西 你可以传递作为一个变量,10,是硬编码。但我明白这是一个实验。
你也可以把语句写成。
select j.*
from mytable t
cross join json_table ( t.jsonstr, '$' columns ( descr path '$.Description' )) j
where t.id = 10;
你可以把它写成动态的
declare
sqlsmt varchar2(200);
id number := 10;
t1 varchar2(30) := 'descr';
t2 varchar2(30) := 'Description';
t3 varchar2(50);
begin
sqlsmt := 'select j.*'
|| ' from mytable t'
|| q'^ cross join json_table ( t.jsonstr, '$' columns ( ^'
|| t1
|| q'^ path '$.^'
|| t2
|| q'^' )) j^'
|| ' where t.id = :id';
dbms_output.put_line(sqlsmt);
execute immediate sqlsmt into t3 using id;
dbms_output.put_line( 'Output Variable: ' || t3);
end;
/
我已经用了 另类引用机制 以避免在语句中使用双引号,但这是可选的。与输出的数据相同。
select j.* from mytable t cross join json_table ( t.jsonstr, '$' columns ( descr path '$.Description' )) j where t.id = :id
Output Variable: TestJSON