14

1 ) I have to make json from oracle select query which has three approach i can follow .

SELECT JSON_ARRAY(json_object('id'         VALUE employee_id, 
                   'data_clob'    VALUE data_clob
                     )) from tablename;

also i have tried with this approach

2) If you are unable to patch/work with that version there is an excellent package written by Lewis Cunningham and Jonas Krogsboell: PL/JSON * http://pljson.sourceforge.net/

It's an excellent package (I have used it in numerous database installations).

The examples included are good and cover most scenarios.

declare 
  ret json;
begin
  ret := json_dyn.executeObject('select * from tab');
  ret.print;
end;
/

Mention In this answer too but not work for such big clob. Return results of a sql query as JSON in oracle 12c

3) The other approach can be we can concatenate the string after the select query.

FOR rec IN (SELECT employee_id, data_clob
                FROM tablename) LOOP
      IF i <> 1 THEN
        v_result := v_result || ',';
      END IF;

      v_result := v_result || '{"employee_id":' || to_char(rec.employee_id) || ',"data_clob": ' || rec.data_clob || '}';

      i := i + 1;
    END LOOP;
    v_result := v_result || ']}'; 

3 approach solve my problem but i don't want to run for loop . Is there is any solution in oracle to handle this .

I check for solution but that don't work without for loop.

https://technology.amis.nl/2015/03/13/using-an-aggregation-function-to-query-a-json-string-straight-from-sql/

url has provide some solution , i tried this but not working .Same issue is coming.

ORA-22835: Buffer too small for CLOB to CHAR or BLOB to RAW conversion (actual: 57416, maximum: 4000)

Could you able to tell me how it can be done ?

Himanshu sharma
  • 7,487
  • 4
  • 42
  • 75
  • What's the version of the Database in this case? Oracle 12c (12.1.0.2) has a native json data type, which might solve your issue (https://docs.oracle.com/database/121/ADXDB/json.htm). There's also a DB parameter MAX_STRING_SIZE which can be set to EXTENDED (gives you 32k of VARCHAR2 variables). Why's all that information for: In Oracle Database, JSON data is stored using the common SQL data types VARCHAR2, CLOB, and BLOB (check this: https://docs.oracle.com/database/122/ADJSN/json-in-oracle-database.htm#ADXDB6371). – g00dy Nov 06 '17 at 06:19
  • The error that you have states that the Parameter MAX_STRING_SIZE is set to STANDARD and you're trying to convert CLOB (4GB) to VARCHAR2 (which is 4000b) in your case. If you need something like 60k, you can't use VARCHAR2, but CLOB only, that is if you want to have the whole data in one single variable. – g00dy Nov 06 '17 at 06:21
  • 1
    JSON_ARRAY and JSON_OBJECT are worthless because they choke on strings more than 4000 chars. How on earth am I supposed to control that?? – Toolkit Sep 11 '18 at 17:33

3 Answers3

11

Since 12.2 version you can do:

select 
  json_object(
     'body' value v_clob 
     returning clob
  )
from dual;

Original answer:

In answer to this question:

3 approach solve my problem but i don't want to run for loop . Is there is any solution in oracle to handle this .

Strings can be concatenated without looping by using Oracle's LISTAGG function:

SELECT '{"employees":[' || LISTAGG('{"employee_id":' || to_char(employee_id)
                      || ',"data_clob":"' || data_clob || '"}', ',')
              WITHIN GROUP (ORDER BY employee_id) || ']}' AS json
FROM tablename;

However, as you've pointed out in the comments, LISTAGG has a limit of 4000 characters. The following is more complex/fiddly but should cope beyond this limit:

SELECT '{"employees":[' || dbms_xmlgen.convert(
         RTRIM(XMLAGG(XMLELEMENT(E,'{"employee_id":' || to_char(employee_id)
                                 || ',"data_clob":"' || data_clob || '"}',',')
                      .EXTRACT('//text()') ORDER BY employee_id).GetClobVal(),',')
       , 1) || ']}' AS json
FROM tablename;

XMLAGG handles CLOBs but the EXTRACT function has the side-effect of escaping certain characters (e.g. from " to &quot;). The query above converts these back (e.g. from &quot; to ") using the dbms_xmlgen.convert function - see this answer for further details.

SQL Fiddle demo: http://sqlfiddle.com/#!4/5b295/40

MrE
  • 19,584
  • 12
  • 87
  • 105
Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
  • No this is not the solution . check out this query in oracle this give error.ORA-22835: Buffer too small for CLOB to CHAR or BLOB to RAW conversion (actual: 57416, maximum: 4000) – Himanshu sharma Nov 06 '17 at 09:20
  • Have edited my answer - please let me know whether the new method works... – Steve Chambers Nov 06 '17 at 10:01
  • @SteveChambers just get rid of the to_char() around data_clob and it should work for clobs >32k without ORA-22835. – kfinity Nov 06 '17 at 20:59
  • 1
    @kfinity Possibly - but the `to_char(data_clob)` was taken from approach (3) in the question, which was described as working. – Steve Chambers Nov 07 '17 at 08:34
  • The first problem with the solution is why used XML method and also does you check it don't give output in form [{record1json},{record2json},{record3json}] , Xml operations are slow then json . If we are using json why not to use json methods . If there are not such appropriate method . Does we can not modify those object or create those object . You should remove to_clob from your second solution. – Himanshu sharma Nov 08 '17 at 07:19
  • Have updated the answer to output valid JSON (naming the array as `"employees"` but of course this could be changed). The answer was purely based off approach (3), which was said to solve the problem - but without the for loop, as requested. Oracle only provides `LISTAGG` and `XMLAGG` as built in aggregate functions for doing this - see https://docs.oracle.com/database/121/SQLRF/functions003.htm#SQLRF20035. How slow is the performance compared to your looping method? Not sure what was meant by the last sentence - did you mean remove `to_char` and if so, why is it included in approach (3)? – Steve Chambers Nov 08 '17 at 08:38
  • 1
    Sorry my fault i have place to_char for data_clob member in question , i have remove that you can also remove that. Second answer worked for me will check in performance point of view and also i will love if some one modify json object methord for that . I accept you answer – Himanshu sharma Nov 08 '17 at 09:28
  • Thanks, have removed the `to_char`s accordingly. – Steve Chambers Nov 08 '17 at 09:34
  • FUNCTION regexp_clob(a_clob IN CLOB) RETURN CLOB IS v_temp_clob CLOB; BEGIN v_temp_clob := a_clob; v_temp_clob := regexp_replace(v_temp_clob, '\\', '\\\\'); v_temp_clob := regexp_replace(v_temp_clob, '"', '\"'); v_temp_clob := regexp_replace(v_temp_clob, chr(8), '\b'); v_temp_clob := regexp_replace(v_temp_clob, chr(12), '\f'); v_temp_clob := regexp_replace(v_temp_clob, chr(10), '\n'); v_temp_clob := regexp_replace(v_temp_clob, chr(13), '\r'); v_temp_clob := regexp_replace(v_temp_clob, chr(9), '\t'); RETURN v_temp_clob; END; add this and regexp_clob(data_clob) – Himanshu sharma Nov 08 '17 at 09:35
  • for esacpe sequence in the clob string. – Himanshu sharma Nov 08 '17 at 09:37
1

By default the new json_* functions return a varchar2(4000). You can change this in the returning clause.

If you have extended data types enabled, you can change this to a varchar2(32767). But only the *agg functions support clob.

from here

SELECT length(JSON_ARRAYAGG( 
         JSON_OBJECT( 
           KEY 'object_type' VALUE object_type, 
           KEY 'object_name' VALUE object_name 
         ) 
       returning clob) 
       ) array_size
FROM   all_objects;

ARRAY_SIZE  
5772072  

18c also has full support for clobs in the JSON* functions

Community
  • 1
  • 1
Toolkit
  • 10,779
  • 8
  • 59
  • 68
1

In 12.2 json_* functions handle clobs fine. Use clause Returning clob

create table t( c clob, constraint t_chk check (c is json));
declare
    v_clob clob;
begin
    for i in 1..10000 loop
        v_clob := v_clob || 'asdasdadasdasdasdasdasdasdasd';
    end loop;

    insert into t(c) 
    select 
        json_object
        (
           'body' value v_clob returning clob
         )
    from
        dual;
end;   
Brzl
  • 41
  • 3