json - 将包级用户定义的记录类型序列化/编码为 JSON

标签 json oracle plsql oracle19c

我正在尝试将 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 functions , Oracle 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不允许

如果您确实希望使用 JSON_OBJECT 来创建 JSON 而不是 JSON_OBJECT_T,您使用的类型将需要预定义(不在 pl/sql block 中)并且您仍然需要定义 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',
                            'Doe',
                            rt_address ('123 Main Street', 'Apartment# 2A', 'London')),
               RT_Customer ('Jane',
                            'Smith',
                            rt_address ('456 Broken Dreams Blvd', NULL, 'Greenville'))));

关于json - 将包级用户定义的记录类型序列化/编码为 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63411696/

相关文章:

oracle - PL/SQL 嵌套过程异常处理

mysql - 将 plsql 函数的值复制到新表中

php - MySQL 表和 JSON 解析。是否有外键?

oracle - T-SQL:如何使用SELECT创建表?

sql - 在 PostgreSQL 中使用 Jsonb_array_elements_text() 的 2 种方法

oracle - 两阶段提交/共享交易

java - 使用本地过程将数据插入数据库或使用最近的框架(如 spring 或 Entity Framework )将数据插入数据库之间有什么区别吗?

sql - PLS-00312 : a positional parameter association may not follow a named association

javascript - 为什么 JSON 末尾会出现一个额外的元素?

php - 如何使用内置的 composer-plugin 创建一个整体的 Composer 包?