Есть несколько вещей, которые могут помочь с динамикой c 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
не должно быть в кавычках ; это не вызывает ошибку, но остановит ее привязку к вашей переменной, как вы ожидаете, поскольку это буквальное значение. У вас также есть часть $.
в этом бите и в значении вашей переменной, но, опять же, это не так далеко.
Как и все динамические c SQL, вы можете указывать только значения для переменных в предложении using
. Вы пытаетесь передать имя столбца в качестве переменной связывания, что не разрешено; поэтому он пытается использовать :t1
в качестве имени выходного столбца, а не desc
; и :t1
недействительное имя. (Также не desc
, поскольку это зарезервированное слово - но либо возникает та же ошибка.) Итак, вам нужно объединить имя столбца, а не связывать его.
Похоже, вы могли бы использовать :t2
для пути хотя; но вы тоже не можете этого сделать, не как ограничение Dynami c SQL, а как ограничение SQL / JSON - если вы зашли так далеко, с допустимым значением переменной, вы все равно получите "ORA -40454: выражение пути не буквальное ". Вы также должны объединить путь с оператором.
Наконец, $[*]
не позволяет сопоставить Description
..., что приводит ко второй подсказке о динамике c SQL; сначала получите запрос stati c, работающий должным образом, а затем сделайте этот динамический c.
Итак, собрав это вместе, вы можете сделать:
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
db <> fiddle