Extracting entire JSON element sub elements - json

I have this bit of code here...
set serveroutput on;
DECLARE
v_response varchar(3000) := '{"content":{"stuff":{"cat":"meow","dog":"woof"}},"http_code":401,"response_code":"-1"}';
v_content varchar(3000);
BEGIN
select json_value(v_response, '$.content') into v_content from dual;
dbms_output.put_line('v_content: ' || v_content);
END;
I would expect the variable v_content to contain something along the lines of '{"stuff":{"cat":"meow","dog":"woof"}'. However it is returning nothing.

JSON_VALUE finds a specified scalar JSON value in JSON data and returns it as a SQL value.
select json_value('{"content":{"stuff":{"cat":"meow","dog":"woof"}},"http_code":401,"response_code":"-1"}', '$.content.stuff.cat') from dual
returned meow
Try this:
DECLARE
je JSON_ELEMENT_T;
jo JSON_OBJECT_T;
content JSON_OBJECT_T;
v_response varchar(3000) := '{"content":{"stuff":{"cat":"meow","dog":"woof"}},"http_code":401,"response_code":"-1"}';
BEGIN
je := JSON_ELEMENT_T.parse(v_response);
IF (je.is_Object) THEN
jo := treat(je AS JSON_OBJECT_T);
content := jo.get_Object('content');
END IF;
DBMS_OUTPUT.put_line(content.to_string);
END;

Related

Scrape data from Apex which created with PL/SQL dynamic content?

I have used PL/SQL dynamic content for creating a report. I need to add functionality to scrape (take data) from this HTML. Moreover, I have SQL which returns data.
How can I do this with APEX region PL/SQL dynamic content?
PL/SQL code for creating HTML tags with data:
declare
l_sql varchar2(2000) := test.function(92500, 2017, 2, 114); --return which select when we dynamical execute this select it will return data
l_columns varchar2(2000) := test.test_function_dynamic_columns_name(92500, 2017, 2, 114);
l_vc_arr2 APEX_APPLICATION_GLOBAL.VC_ARR2;
v_tableclob clob := '<table summary="" class="a-IRR-table" id="2212903112260009" role="presentation">';
v_rowclob clob;
v_rowclob_1 clob;
begin
l_vc_arr2 := APEX_UTIL.STRING_TO_TABLE(l_columns);
v_tableclob := v_tableclob||'<tr>';
v_tableclob := v_tableclob ||'<th class="a-IRR-header">';
v_tableclob := v_tableclob ||REPLACE(REPLACE(l_columns,'"',' '),':','</th><th class="a-IRR-header">');
v_tableclob := v_tableclob ||'</th></tr>';
FOR z IN 1..l_vc_arr2.count LOOP
if l_vc_arr2(z) = '"SUM"' then
v_rowclob := v_rowclob ||'<td class="summation">''||t.'||l_vc_arr2(z)||'||''</td>';
v_rowclob_1 := v_rowclob_1 || '<td id="total_sum"></td>';
else
v_rowclob := v_rowclob ||'<td>''||t.'||l_vc_arr2(z)||'||''</td>';
v_rowclob_1 := v_rowclob_1 || '<td></td>';
end if;
end loop;
execute immediate
'
declare
begin
htp.p('''||v_tableclob||''');
for t in ('||l_sql||') loop
htp.p(''<tr>'||v_rowclob||'</tr>'');
end loop;
htp.p(''<tr>'');
htp.p('''|| v_rowclob_1 ||''');
htp.p(''</tr>'');
htp.p(''</table>'');
end;';
end;

Extracting very long string from JSON to CLOB

I'm trying to extract a very long string into clob from json_object_t and got some weird database behaviour (12.2c) with json_object_t.get_clob(key) method.
There is a sample code than does following:
DECLARE
l_data CLOB := '{"text": "very long string about 1M chars"}';
l_json json_object_t;
l_text CLOB := EMPTY_CLOB();
BEGIN
l_json := json_object_t.parse(l_data);
l_text := l_json.get_clob('text');
dbms_output.put_line('got ' || dbms_lob.getlength(l_text) || ' chars');
END;
When string length in a 'text' key is less than 32k chars, get_clob method works just fine and shows appropriate result, but with longer strings it produces an empty clob with zero length, just like get_string, but without 'character string buffer too small' exception.
I've tried to get same data via json_table query, but it cannot extract data to clob column at all, only varchar/number is allowed.
Is that a bug or am I doing something wrong? Is there any other ways to extract long strings from JSON keys?
I work with Oracle Database JSON Store group and would be happy to assist you with this issue you're facing. Could you try the alternate get_Clob procedure instead of this function and tell us what the behavior is?
Signature:
MEMBER PROCEDURE get_Clob(key VARCHAR2, c IN OUT CLOB)
Please try this:
DECLARE
content_json CLOB := '{"value":"';
content_json_end CLOB := '"}';
content_tmp CLOB := 'ab';
l_json json_object_t;
l_text CLOB := EMPTY_CLOB();
tmp clob;
BEGIN
-- 13 gives 16K
-- 14 gives 32K
FOR count IN 1 .. 14
loop
dbms_lob.append(content_tmp, content_tmp); -- a bad append for now
END loop;
dbms_lob.append(content_json, content_tmp);
dbms_lob.append(content_json, content_json_end);
l_json := json_object_t.parse(content_json);
l_json.get_clob('value', l_text); -- !!! TRY THIS PROC get_Clob
--l_text := l_json.get_clob('value');
dbms_output.put_line('Lob size in Kb: ');
dbms_output.put_line(dbms_lob.getLength(l_text) / 1024);
END;
/
Looking forward to your findings..
This works as well. Instead using the the get_clob method, use c:
DECLARE
CURSOR crsrJSON IS
SELECT
json_object( 'employee_id' VALUE employee_id,
'first_name' VALUE first_name,
'last_name' VALUE last_name,
'email' VALUE email,
'phone_number' VALUE phone_number,
'hire_date' VALUE to_char(hire_date,'MM/DD/YYYY'),
'job_id' VALUE job_id,
'salary' VALUE nvl(salary,0),
'commission_pct' VALUE nvl(commission_pct,0),
'manager_id' VALUE NVL(manager_id,0),
'department_id' VALUE NVL(department_id,0),
'department_name' VALUE (select department_name from departments x where x.department_id = hr.department_id),
'job_title' VALUE (select job_title from jobs x where x.job_id = hr.job_id)) emp_data
FROM
employees hr;
js_array JSON_ARRAY_T := new JSON_ARRAY_T;
json_obj JSON_OBJECT_T := JSON_OBJECT_T();
json_clob CLOB := EMPTY_CLOB();
BEGIN
FOR data_rec IN crsrJSON LOOP
js_array.append(JSON_ELEMENT_T.parse(data_rec.emp_data));
END LOOP;
json_obj.put('data',js_array);
IF json_obj.has('data') THEN
json_clob := json_obj.to_clob;
DBMS_OUTPUT.PUT_LINE(json_clob);
ELSE
DBMS_OUTPUT.PUT_LINE('Nope');
END IF;
END;
with data as
( select
xmlelement(e,regexp_replace('{"name":"'||colname||'"}', '[[:cntrl:]]', ''),',') col1
from tblname
)
select
rtrim(replace(replace(replace(xmlagg(col1).getclobval(),'&'||'quot;','"'),'<E>',''),'</E>',''),',')
as very_long_json
from data;

Run functions recursively

I have 2 function function1 and function2.
Now I'm wondering how to run them recursively.
Maybe I will describe it:
Input of function1 is table of array from function2 output. Output of function1 is also table of array which is input for function2 and so on.
While function1 is returning some values then function2 should be execute with that values.
When function2 return some values then function1 should be execute.
Function1 and function2 should be execute until one of them return null. Is it possible to do in pl/sql? Could you give me some tips? How to correctly convey the variables?
EDIT:
Generally it should looks:
declare
tab2 num_array;
v_Return NUM_ARRAY;
v_Return2 NUM_ARRAY;
BEGIN
select ID bulk collect into tab2 from account;
v_Return := function1(tab2);
if v_return is not null then
v_return2 :=function2(v_return);
--and now iteration:
if v_return2.count>0 then
v_Return := function1(v_return2);
if v_return.count>0 then
v_return2 :=function2(v_return);
if v_return2.count>0 then
v_Return := function1(v_return2);
if v_return..count>0 then
v_return2 :=function2(v_return);
-- and so on
END;
Of course I want to avoid doing something like that, can it be dynamically?
----edit 2
while(num=1)
loop
if v_return.count>0 then
num := 1;
v_return2 :=function2(v_return);
if v_return2.count>0 then
num :=1;
v_Return := function1(v_return2);
else num :=0;
end if;
else num :=0;
end if;
end loop;
END;
How about using a simple loop?
loop
v_return2 := function2(v_return);
exit when v_return2.count = 0;
v_return := function1(v_return2);
exit when v_return.count = 0;
end loop;

Throws the output ########### in sql developer

when i execute the below script it doesnt print the value. Kinldy help me to solve as soon as possible
set serveroutput on;
declare
v_upd_value VARCHAR2(50);
v_dscnt_pcnt NUMBER := '22222222.22';
begin
v_upd_value := trim(to_char(v_dscnt_pcnt,'9999990.99'));
dbms_output.put_line('update value :'||v_upd_value);
end;
thanks in advance
You need to add one more 9 in to_char function as below.
declare
v_upd_value VARCHAR2(50);
v_dscnt_pcnt NUMBER := '22222222.22';
begin
v_upd_value := trim(to_char(v_dscnt_pcnt,'99999990.99'));
dbms_output.put_line('update value :'||v_upd_value);
end;
Hope this helps..

Return value of stored functions in MyDAC

I am working with Devart's MyDac and MySQL Server 5.0.41. Here is a section from the documentation on executing stored procedures with TMyConnection.ExecProc:
Note: Stored functions unlike stored procedures return result values that are obtained internally through the RESULT parameter. You will no longer have to provide anonymous value in the Params array to describe the result of the function. The stored function result is obtained from the Params[0] indexed property or with the ParamByName('RESULT') method call.
They also give an example on how to execute a stored function:
aStringVariable1 := TMyConnection.ExecProc('StoredFunctionName',['Param1','Param2']);
aStringVariable2 := TMyConnection.ParamByName('Result').AsString;
By Following these examples, my execution of the stored functions are returning Param1 in the variable aStringVariable2.The execution of the functions in the Query Browser returns the right results. Any pointers on the right way to execute stored functions in MyDAC with TMyConnection or TMyStoredProc will be appreciated.
Thanks in advance.
Here is the code we use to call stored procedures - hope it helps
function TDbControl.DatabaseStoredProc(FConnectionsAddr: integer; SpName: string;var Params: TDAParams): boolean;
var
MyStoredProc: TMyStoredProc;
PramsTxt: String;
Idx, Idx2: Integer;
begin
result := False;
MyStoredProc := nil;
try
try
MyStoredProc := TMyStoredProc.Create(nil);
MyStoredProc.Connection := TMyConnection(FConnectionsAddr);
MyStoredProc.StoredProcName := SpName;
MyStoredProc.ParamCheck := False;
if assigned(Params) then
begin
for Idx := 0 to Params.Count - 1 do
begin
MyStoredProc.ParamByName(Params[Idx].Name).DataType := Params[Idx].DataType;
MyStoredProc.ParamByName(Params[Idx].Name).Value := Params[Idx].Value;
end;
end;
MyStoredProc.Execute;
if assigned(Params) then
begin
for Idx := 0 to Params.Count - 1 do
begin
if (Params[Idx].ParamType = ptOutput ) then
Params[Idx].Value := MyStoredProc.ParamByName(Params[Idx].Name).Value;
end;
end;
result := True;
except
on E: Exception do
begin
PramsTxt := '';
if assigned(Params) then
begin
for Idx2 := 0 to Params.Count - 1 do
begin
PramsTxt := PramsTxt + Params.Items[Idx2].Name + '=' + Params[Idx2].AsString + ',';
end;
end;
LogText(FConnectionsAddr, 'DatabaseStoredProc Err:' + E.Message + ' SpName:' + SpName + ' Prams:' + PramsTxt);
raise ;
end;
end;
finally
FreeAndNil(MyStoredProc);
end;
end;