序列化/编组包级别用户将记录类型定义为JSON

问题描述

我正在尝试将PL / SQL包中定义的记录类型转换为JSON。

我发现在SQL中,我可以使用select json_object(*) from SomeTable返回具有表中每一列属性的对象,但是对于PL / SQL代码中的记录类型,我似乎无法做到这一点。

示例程序包,其中包含类型和根据类型返回(序列化)json的函数:

create or replace package Customer as
  type RT_Address is record (
    Line1 varchar2(100),Line2 varchar2(100),City varchar2(100)
  );

  type RT_Customer is record (
    FirstName varchar2(100),LastName varchar2(100),Address RT_Address
  );

  function AsJson(P_Customer RT_Customer)
  return varchar2;

end;

create or replace package body devvanessa.Customer as

  function AsJson(P_Customer RT_Customer)
  return varchar2 is
    V_DOM jdom_t;
    V_JSON json_object_t;
    V_JSONBody varchar2(4000);
  begin

    V_JSON := json_object(P_Customer); -- PLS-00103: Encountered the symbol when expecting one of the following: . ( * @ % & - + / at mod remainder rem <een exponent (**)> || multiset value

    if V_DOM.append(P_CUSTOMER) then -- PLS-00306: wrong number or types of arguments
      null;
    end if;
    V_JSONBody := V_Json.STRINGIFY;

    return V_JSONBody;
  end;

end;

上面的内容略有简化,因为我实际上想存储此json并对其进行其他操作,但这确实显示了我的问题的核心:

如何在PL / SQL中将记录类型转换为Json,而无需分别指定所有单个字段。 我也很好奇它会如何工作。

我一直在搜索各种资源,例如documentation on JSON functionsOracle 19's JSON documentation,以及我在json_object_tjdom_t类型上获得的代码完成提示,但到目前为止我完全找不到任何证据。

这将起作用:

    V_JSon.Put('FirstName',P_Customer.FirstName);
    -- repeated for each property

通过这种方式获取json,但需要我分别指定每个字段。

解决方法

JSON_OBJECT_T没有采用记录类型的构造函数,因此您将需要显式定义每个键/值以定义JSON。您尝试执行的操作不需要JDOM_T。以下是有关如何将记录类型转换为JSON并返回的示例。

DECLARE
    TYPE RT_Address IS RECORD
    (
        Line1    VARCHAR2 (100),Line2    VARCHAR2 (100),City     VARCHAR2 (100)
    );

    TYPE RT_Customer IS RECORD
    (
        FirstName    VARCHAR2 (100),LastName     VARCHAR2 (100),Address      RT_Address
    );

    l_customer1   rt_customer
        := rt_customer ('John','Doe',rt_address ('123 Main Street','Apartment# 2A','London'));
    l_customer2   rt_customer
        := rt_customer ('Jane','Smith',rt_address ('456 Broken Dreams Blvd',NULL,'Greenville'));
    l_json        json_object_t;
    l_record      rt_customer;

    FUNCTION customer_record_to_json (P_Customer RT_Customer)
        RETURN json_object_t
    IS
        l_address    json_object_t := json_object_t ();
        l_customer   json_object_t := json_object_t ();
    BEGIN
        l_address.put ('Line1',p_customer.address.line1);
        l_address.put ('Line2',p_customer.address.line2);
        l_address.put ('City',p_customer.address.city);

        l_customer.put ('FirstName',p_customer.firstname);
        l_customer.put ('LastName',p_customer.lastname);
        l_customer.put ('Address',l_address);

        RETURN l_customer;
    END;

    FUNCTION customer_json_to_record (p_customer_json json_object_t)
        RETURN rt_customer
    IS
        l_address_json   json_object_t := json_object_t ();

        l_address        rt_address;
        l_customer       rt_customer;
    BEGIN
        l_address_json := p_customer_json.get_object ('Address');
        l_address.line1 := l_address_json.get_string ('Line1');
        l_address.line2 := l_address_json.get_string ('Line2');
        l_address.city := l_address_json.get_string ('City');

        l_customer.firstname := p_customer_json.get_string ('FirstName');
        l_customer.lastname := p_customer_json.get_string ('LastName');
        l_customer.address := l_address;
        RETURN l_customer;
    END;
BEGIN
    l_json := customer_record_to_json (l_customer1);
    DBMS_OUTPUT.put_line ('Customer 1 (JSON): ' || l_json.stringify);
    l_record := customer_json_to_record (l_json);
    DBMS_OUTPUT.put_line ('Customer 1 (Record) (FirstName): ' || l_record.firstname);
    DBMS_OUTPUT.put_line ('Customer 1 (Record) (LastName): ' || l_record.lastname);
    DBMS_OUTPUT.put_line ('Customer 1 (Record) (Line1): ' || l_record.address.line1);
    DBMS_OUTPUT.put_line ('Customer 1 (Record) (Line2): ' || l_record.address.line2);
    DBMS_OUTPUT.put_line ('Customer 1 (Record) (City): ' || l_record.address.city);

    l_json := customer_record_to_json (l_customer2);
    DBMS_OUTPUT.put_line ('Customer 2 (JSON): ' || l_json.stringify);
    l_record := customer_json_to_record (l_json);
    DBMS_OUTPUT.put_line ('Customer 2 (Record) (FirstName): ' || l_record.firstname);
    DBMS_OUTPUT.put_line ('Customer 2 (Record) (LastName): ' || l_record.lastname);
    DBMS_OUTPUT.put_line ('Customer 2 (Record) (Line1): ' || l_record.address.line1);
    DBMS_OUTPUT.put_line ('Customer 2 (Record) (Line2): ' || l_record.address.line2);
    DBMS_OUTPUT.put_line ('Customer 2 (Record) (City): ' || l_record.address.city);
END;

更新

仅可以JSON_OBJECT(*)创建一个JSON对象,但是*扩展不适用于记录类型,因为您将获得一个ORA-40579: star expansion is not allowed

如果您确实希望使用JSON_OBJECT来创建JSON而不是JSON_OBJECT_T,则需要预定义所使用的类型(不在pl / sql块中),并且仍然需要定义每个字段在JSON结构中。您还需要定义一个RT_CUSTOMER类型的表类型,以便您可以从中查询。

CREATE TYPE RT_Address AS OBJECT (Line1 VARCHAR2 (100),Line2 VARCHAR2 (100),City VARCHAR2 (100));

CREATE TYPE RT_Customer AS OBJECT
(
    FirstName VARCHAR2 (100),LastName VARCHAR2 (100),Address RT_Address
);

CREATE TYPE rt_customer_t AS TABLE OF rt_customer;

SELECT json_object (
           'firstname' VALUE firstname,'lastname' VALUE lastname,'address' VALUE
               json_object ('line1' VALUE TREAT (address AS rt_address).line1,'line2' VALUE TREAT (address AS rt_address).line2,'city' VALUE TREAT (address AS rt_address).city)) as customer
  FROM TABLE (
           rt_customer_t (
               RT_Customer ('John','London')),RT_Customer ('Jane','Greenville'))));

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...