Может выполняться немедленно, может использоваться с JSON_TABLE - PullRequest
0 голосов
/ 17 июня 2020

Мне нужно преобразовать JSON в таблицу данных (столбцы значений ключа) в Oracle 12 c v12.1.0.2

Так, например, есть строка JSON, например

{"ID": 10, "Description": "TestJSON", "status":"New"}

Мне нужно это преобразовать в:

Column1          Column2
------------------------------------
ID                  10
Description         TestJSON
status              New

Теперь моя строка JSON может изменить количество атрибутов, и, следовательно, мне нужно сохранить динамику преобразования c.

Я пробовал использовать немедленное выполнение:

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 12 c V1. Но мне действительно нужно динамически извлекать столбцы из JSON.

1 Ответ

1 голос
/ 17 июня 2020

Есть несколько вещей, которые могут помочь с динамикой 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...