【问题标题】:How to generate JSON in Oracle for a CLOB that is > 32k (e.g. 60,000 characters)?如何在 Oracle 中为大于 32k(例如 60,000 个字符)的 CLOB 生成 JSON?
【发布时间】:2017-11-03 09:54:17
【问题描述】:

1) 我必须从 oracle 选择查询中生成 json,我可以遵循三种方法。

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

我也尝试过这种方法

2) 如果您无法修补/使用该版本,可以使用 Lewis Cunningham 和 Jonas Krogsboell 编写的出色软件包:PL/JSON * http://pljson.sourceforge.net/

这是一个很棒的包(我在很多数据库安装中都使用过它)。

包含的示例很好,涵盖了大多数场景。

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

在这个答案中也提到但不适用于这么大的笨蛋。 Return results of a sql query as JSON in oracle 12c

3) 另一种方法是我们可以在选择查询之后连接字符串。

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 种方法解决了我的问题,但我不想运行 for 循环。 oracle有什么解决方案来解决这个问题吗?

我检查了解决方案,但没有 for 循环就无法工作。

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

url 提供了一些解决方案,我试过了,但没有用。同样的问题来了。

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

你能告诉我怎么做吗?

【问题讨论】:

  • 这种情况下数据库的版本是多少? Oracle 12c (12.1.0.2) 具有本机 json 数据类型,它可能会解决您的问题 (docs.oracle.com/database/121/ADXDB/json.htm)。还有一个 DB 参数 MAX_STRING_SIZE 可以设置为 EXTENDED(为您提供 32k 的 VARCHAR2 变量)。为什么所有这些信息用于:在 Oracle 数据库中,JSON 数据使用常见的 SQL 数据类型 VARCHAR2、CLOB 和 BLOB 进行存储(请查看:docs.oracle.com/database/122/ADJSN/…)。
  • 您遇到的错误表明参数 MAX_STRING_SIZE 设置为 STANDARD,并且您正在尝试将 CLOB (4GB) 转换为 VARCHAR2 (即 4000b)。如果您需要 60k 之类的数据,则不能使用 VARCHAR2,而只能使用 CLOB,也就是说,如果您希望将全部数据放在一个变量中。
  • JSON_ARRAY 和 JSON_OBJECT 毫无价值,因为它们会阻塞超过 4000 个字符的字符串。我到底应该如何控制它??

标签: sql json oracle plsql clob


【解决方案1】:

从 12.2 版本开始你可以这样做:

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

原答案:

回答这个问题:

3 种方法解决了我的问题,但我不想运行 for 循环。 oracle有什么解决方案来解决这个问题吗?

使用 Oracle 的 LISTAGG 函数可以在不循环的情况下连接字符串:

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

但是,正如您在 cmets 中指出的那样,LISTAGG 有 4000 个字符的限制。以下内容更复杂/更复杂,但应超出此限制:

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 处理CLOBs,但EXTRACT 函数具有转义某些字符的副作用(例如,从"&amp;quot;)。上面的查询使用dbms_xmlgen.convert 函数将这些转换回来(例如,从&amp;quot;") - 有关详细信息,请参阅this answer

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

【讨论】:

  • 不,这不是解决方案。在 oracle 中查看这个查询,这给出了错误。ORA-22835:缓冲区太小,无法将 CLOB 转换为 CHAR 或 BLOB 到 RAW 转换(实际:57416,最大值:4000)
  • 已编辑我的答案 - 请让我知道新方法是否有效...
  • @SteveChambers 只是摆脱了 data_clob 周围的 to_char() ,它应该适用于没有 ORA-22835 的 >32k 的 clob。
  • @kfinity 可能 - 但to_char(data_clob) 取自问题中的方法(3),被描述为有效。
  • 对不起,我有问题的 data_clob 成员的 to_char 位置,我已删除,您也可以删除它。对我有用的第二个答案将从性能角度检查,如果有人为此修改 json 对象方法,我也会喜欢。我接受你的回答
【解决方案2】:

默认情况下,新的 json_* 函数返回 varchar2(4000)。您可以在返回子句中更改它。

如果您启用了扩展数据类型,您可以将其更改为 varchar2(32767)。但只有 *agg 函数支持 clob。

来自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 还完全支持 JSON* 函数中的 clob

【讨论】:

    【解决方案3】:

    在 12.2 中,json_* 函数可以很好地处理 clob。使用子句返回 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;   
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-16
      • 2012-11-14
      • 1970-01-01
      相关资源
      最近更新 更多