работать с JSON в Oracle - PullRequest
       2

работать с JSON в Oracle

21 голосов
/ 02 ноября 2011

Есть ли простой способ работы с JSON в Oracle?У меня есть стандартная процедура, которую я использую для вызова веб-сервисов довольно часто, JSON - это формат, с которым я знаком в контексте веб-разработки, но как лучше всего работать с json в рамках хранимой процедуры?Например, взять ответ CLOB из URI, преобразовать его в объект JSON и получить из него значение?

Для справки, вот процедура, которую я использовал для получения URL-адресов

create or replace procedure macp_URL_GET(url_resp in out clob, v_url in varchar2) is
   req     Utl_Http.req;
   resp    Utl_Http.resp;
   NAME    VARCHAR2 (255);
   VALUE   VARCHAR2 (1023);
   v_msg   VARCHAR2 (80);
   v_ans clob;
--   v_url   VARCHAR2 (32767) := 'http://www.macalester.edu/';
BEGIN
   /* request that exceptions are raised for error Status Codes */
   Utl_Http.set_response_error_check (ENABLE => TRUE );
   /* allow testing for exceptions like Utl_Http.Http_Server_Error */
   Utl_Http.set_detailed_excp_support (ENABLE => TRUE );
   /*
   Utl_Http.set_proxy (
      proxy                 => 'www-proxy.us.oracle.com',
      no_proxy_domains      => 'us.oracle.com'
   );
   */
   req := Utl_Http.begin_request (url => v_url, method => 'GET');
   /*
    Alternatively use method => 'POST' and Utl_Http.Write_Text to
    build an arbitrarily long message
  */

  /*
   Utl_Http.set_authentication (
      r              => req,
      username       => 'SomeUser',
      PASSWORD       => 'SomePassword',
      scheme         => 'Basic',
      for_proxy      => FALSE      --this info is for the target Web server 
   );
   */

   Utl_Http.set_header (r => req, NAME => 'User-Agent', VALUE => 'Mozilla/4.0');
   resp := Utl_Http.get_response (r => req);
   /*
   DBMS_OUTPUT.put_line ('Status code: ' || resp.status_code);
   DBMS_OUTPUT.put_line ('Reason phrase: ' || resp.reason_phrase);
   FOR i IN 1 .. Utl_Http.get_header_count (r => resp)
   LOOP
      Utl_Http.get_header (r => resp, n => i, NAME => NAME, VALUE => VALUE);
      DBMS_OUTPUT.put_line (NAME || ': ' || VALUE);
   END LOOP;
   */
--test
   BEGIN
      LOOP
         Utl_Http.read_text (r => resp, DATA => v_msg);
         --DBMS_OUTPUT.put_line (v_msg);
         v_ans := v_ans || v_msg;
         url_resp := url_resp || v_msg;
      END LOOP;
   EXCEPTION
      WHEN Utl_Http.end_of_body
      THEN
         NULL;
   END;
--test
   Utl_Http.end_response (r => resp);


   --url_resp := v_ans;

EXCEPTION
   /*
    The exception handling illustrates the use of "pragma-ed" exceptions
    like Utl_Http.Http_Client_Error. In a realistic example, the program
    would use these when it coded explicit recovery actions.

    Request_Failed is raised for all exceptions after calling
    Utl_Http.Set_Detailed_Excp_Support ( ENABLE=>FALSE )
    And it is NEVER raised after calling with ENABLE=>TRUE
  */
   WHEN Utl_Http.request_failed
   THEN
      DBMS_OUTPUT.put_line (
         'Request_Failed: ' || Utl_Http.get_detailed_sqlerrm
      );
      url_resp :='Request_Failed: ' || Utl_Http.get_detailed_sqlerrm;
   /* raised by URL http://xxx.oracle.com/ */
   WHEN Utl_Http.http_server_error
   THEN
      DBMS_OUTPUT.put_line (
         'Http_Server_Error: ' || Utl_Http.get_detailed_sqlerrm
      );
      url_resp := 'Http_Server_Error: ' || Utl_Http.get_detailed_sqlerrm;
   /* raised by URL http://otn.oracle.com/xxx */
   WHEN Utl_Http.http_client_error
   THEN
      DBMS_OUTPUT.put_line (
         'Http_Client_Error: ' || Utl_Http.get_detailed_sqlerrm
      );
      url_resp := 'Http_Client_Error: ' || Utl_Http.get_detailed_sqlerrm;
   /* code for all the other defined exceptions you can recover from */
   WHEN OTHERS
   THEN
      DBMS_OUTPUT.put_line (SQLERRM);
      url_resp := SQLERRM;
END;

Затем, чтобы проверить это

begin
  macp_url_get(url_resp => :url_resp,
               'http://maps.googleapis.com/maps/api/geocode/json?address=55105&sensor=false');
end;

(я знаю, что googleapi разрешит xml-ответ, но есть другие веб-API, которые я регулярно использую по умолчанию для JSON)

Ответы [ 6 ]

18 голосов
/ 09 мая 2012

Я начал использовать эту библиотеку, и она кажется многообещающей: https://github.com/pljson/pljson

Простота установки, и примеры хороши.

Чтобы использовать библиотеку в своем примере, добавьте этипеременные вашей процедуры ..

mapData     json;
results     json_list;
status      json_value;
firstResult json;
geometry    json;

....

Затем вы можете манипулировать ответом как объектом json.

-- convert the result from the get to a json object, and show some results.
mapData := json(v_ans);

-- Show the status of the request
status := mapData.get('status');
dbms_output.put_line('Status = ' || status.get_string());

IF (status.get_string() = 'OK') THEN
  results := json_list(mapData.get('results'));
  -- Grab the first item in the list
  resultObject := json(results.head);

  -- Show the human readable address 
  dbms_output.put_line('Address = ' || resultObject.get('formatted_address').to_char() );
  -- Show the json location data 
  dbms_output.put_line('Location = ' || resultObject.get('geometry').to_char() );
END IF;

Запуск этого кода приведет к выводуэто к выводу DBMS:

Status = OK
Address = "St Paul, MN 55105, USA"
Location = {
  "bounds" : {
    "northeast" : {
      "lat" : 44.9483849,
      "lng" : -93.1261959
    },
    "southwest" : {
      "lat" : 44.9223829,
      "lng" : -93.200307
    }
  },
  "location" : {
    "lat" : 44.9330076,
    "lng" : -93.16290629999999
  },
  "location_type" : "APPROXIMATE",
  "viewport" : {
    "northeast" : {
      "lat" : 44.9483849,
      "lng" : -93.1261959
    },
    "southwest" : {
      "lat" : 44.9223829,
      "lng" : -93.200307
    }
  }
}
4 голосов
/ 03 февраля 2015

Следует отметить, что в Oracle 12c имеется некоторая встроенная поддержка JSON.Однако я не думаю, что в текущей форме это так же полезно, как в PLJSON, включенном в другой ответ.

Чтобы использовать эту функцию, создайте таблицу с полем BLOB, CLOB или Varchar2 и добавьте ограничение наэто "колонка это JSON".Это обеспечивает проверку синтаксиса JSON для этого столбца.

Пока установлено ограничение "IS JSON", вы можете получить доступ к значениям JSON внутри, используя точечную нотацию из SQL.Мне кажется, это не обеспечивает такую ​​мощную манипуляцию, как PLJSON.Вы также можете создать XMLType и затем преобразовать его в JSON.

Полезные ссылки:
Документы Oracle
Хороший учебник и примеры
Учебник, включающий XML в JSON

2 голосов
/ 22 апреля 2016

Oracle 12c теперь имеет встроенную поддержку JSON :

База данных Oracle изначально поддерживает данные JavaScript Object Notation (JSON) с функциями реляционной базы данных, включая транзакции, индексацию, декларативные запросы и представления

Данные JSON и данные XML можно использовать в базе данных Oracle аналогичным образом.В отличие от реляционных данных, оба могут храниться, индексироваться и запрашиваться без какой-либо необходимости в схеме, определяющей данные.Oracle Database изначально поддерживает JSON с функциями реляционной базы данных, включая транзакции, индексацию, декларативные запросы и представления.

Данные JSON часто хранятся в базах данных NoSQL, таких как Oracle NoSQL Database и Oracle Berkeley DB.Они позволяют хранить и извлекать данные, которые не основаны на какой-либо схеме, но не предлагают строгие модели согласованности реляционных баз данных.

Чтобы компенсировать этот недостаток, иногда используется реляционная база данных параллельно сбаза данных NoSQL.Приложения, использующие данные JSON, хранящиеся в базе данных NoSQL, должны сами обеспечить целостность данных.

Собственная поддержка JSON Oracle Database устраняет такие обходные пути.Он предоставляет все преимущества возможностей реляционной базы данных для использования с JSON, включая транзакции, индексацию, декларативные запросы и представления.

Запросы к базе данных Oracle являются декларативными.Вы можете объединить данные JSON с реляционными данными.И вы можете проецировать данные JSON реляционно, делая их доступными для реляционных процессов и инструментов.Вы также можете запросить из базы данных данные JSON, которые хранятся вне базы данных во внешней таблице.

Вы можете получить доступ к данным JSON, хранящимся в базе данных, так же, как и к другим данным базы данных, включая использование OCI., .NET и JDBC.

В отличие от данных XML, которые хранятся с использованием типа данных SQL XMLType, данные JSON хранятся в базе данных Oracle с использованием типов данных SQL VARCHAR2, CLOB и BLOB.Oracle рекомендует всегда использовать проверочное ограничение is_json, чтобы убедиться, что значения столбцов являются действительными экземплярами JSON

2 голосов
/ 06 декабря 2011

Я написал эту библиотеку: http://reseau.erasme.org/pl-sql-library-for-JSON?lang=en,, и это прекрасно работает, чтобы получить ответ json в таблицу plsql.

Если вы хотите только извлечь данные Oracle и преобразовать их в Json, эта библиотека немного "тяжелая для использования" ... Я могу предложить вам другой код, делающий это лучше и быстрее:

create or replace package jsonfly as

procedure open_object(k varchar2 default null);
procedure close_object;
procedure open_array (k varchar2 default null);
procedure close_array;
procedure separation;
procedure member(k varchar2, v varchar2);
procedure member(k varchar2, n number);
procedure send;
end;
/

create or replace package body jsonfly as
--------------------------------------------------------------------------------
-- package pour générer du JSON, envoyé à la volé
--------------------------------------------------------------------------------
type tCache is table of varchar2(2000) index by binary_integer;

g_openBrace         constant varchar2(2) := '{ ';
g_closeBrace        constant varchar2(2) := ' }';
g_openBracket       constant varchar2(2) := '[ ';
g_closeBracket      constant varchar2(2) := ' ]';
g_stringDelimiter   constant varchar2(1) := '"';
g_Affectation       constant varchar2(3) := ' : ';
g_separation        constant varchar2(3) := ', ';
g_CR                constant varchar2(1) := Chr(10); -- used to indent the JSON object correctly
g_spc               constant varchar2(2) := '  ';     -- used to indent the JSON object correctly
g_js_comment_open   constant varchar2(20) := '/*-secure-\n'; -- used to prevent from javascript hijacking
g_js_comment_close  constant varchar2(20) := '\n*/';          -- used to prevent from javascript hijacking

--isObjectOpened  boolean := false;
--isArrayOpened   boolean := false;
t tCache;
i number := 1;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
procedure p(s  varchar2) is
begin
    t(i) := s;
    i := i + 1;
end;
--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
function encap (s varchar2) return varchar2 is
begin
    return g_stringdelimiter || s || g_stringdelimiter;
end;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
function encode_string(p_string varchar2) return varchar2 is
begin
    return replace(replace(replace(replace(replace(replace(replace(replace(p_string, 
        '\', '\\'), 
        '"', '\"'), 
        '/', '\/'), 
        chr(8), '\b'), 
        chr(9), '\t'), 
        chr(10), '\n'), 
        chr(12), '\f'), 
        chr(13), '\r');
end;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
procedure open_object(k varchar2 default null) is
begin    
    if ( k is null ) then 
        p(g_openbrace);
    else 
        p( encap(k) || g_affectation || g_openbrace);
    end if; 
end;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
procedure close_object is
begin
    if (t(i-1) = g_separation) then
        i := i - 1;
    end if; 
    p(g_closebrace);
    separation();
end;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
procedure open_array (k varchar2 default null) is
begin    
    if ( k is null ) then 
    p(g_openbracket);
    else 
        p( encap(k) || g_affectation || g_openbracket);
    end if; 
end;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
procedure close_array is
begin
    if (t(i-1) = g_separation) then
        i := i - 1;
    end if; 
    p(g_closebracket);
    separation();
end;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
procedure separation is
begin
    p(g_separation);
end;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
procedure key(k varchar2) is
begin
   p( encap(k) || g_affectation);
end;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
procedure value(v varchar2) is
begin
   p(v);
end;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
procedure member(k varchar2, v varchar2) is
begin
    p( encap(k) || g_affectation || encap(encode_string(v)));
    p(g_separation);
end;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
procedure member(k varchar2, n number) is
begin
    p( encap(k) || g_affectation || n );
    p(g_separation);
end;

--------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------
procedure send is
begin
    if (t(i-1) = g_separation) then
        t.delete(i-1);
    end if; 

    i := t.first;
    while (i is not null) loop
        htp.p(t(i));
        i := t.next(i);
    end loop;
end;


end jsonfly;
/
1 голос
/ 27 января 2016

Oracle APEX 5.0 поддерживает JSON с использованием пакета APEX_JSON . Я не использовал это, но это выглядит интересно, и я попросил, чтобы моя команда исследовала это. Наш вариант использования - возможность передавать данные JSON в качестве входного параметра в хранимую процедуру из приложения nodejs.

0 голосов
/ 21 января 2019

Жизнь счастлива, попробуйте это:

CLOB или 20000000 символов JSON

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...