【问题标题】:How to use Oracle JSON_VALUE如何使用 Oracle JSON_VALUE
【发布时间】:2021-02-12 11:08:10
【问题描述】:

我正在处理触发器。

declare
  v_time number(11, 0);
begin
for i in 0..1
loop
  select JSON_VALUE(body, '$.sections[0].capsules[0].timer.seconds') into v_time from bodycontent where contentid=1081438;
dbms_output.put_line(v_time);
end loop;
end;

但是,索引引用不会变成动态的。

like JSON_VALUE(body, '$.sections[i].capsules[i].timer.seconds')

有什么办法可以做到吗?

【问题讨论】:

    标签: sql json oracle stored-procedures json-value


    【解决方案1】:

    你可以使用JSON_TABLE:

    declare
      v_time number(11, 0);
    begin
      for i in 0..1 loop
        SELECT time
        INTO   v_time
        FROM   bodycontent b
               CROSS APPLY
               JSON_TABLE(
                 b.body,
                 '$.sections[*]'
                 COLUMNS (
                   section_index FOR ORDINALITY,
                   NESTED PATH '$.capsules[*]'
                   COLUMNS (
                     capsule_index FOR ORDINALITY,
                     time NUMBER(11,0) PATH '$.timer.seconds'
                   )
                 )
               ) j
        WHERE  j.section_index = i + 1
        AND    j.capsule_index = i + 1
        AND    b.contentid=1081438;
    
        dbms_output.put_line(v_time);
      end loop;
    end;
    /
    

    其中,对于测试数据:

    CREATE TABLE bodycontent ( body CLOB CHECK ( body IS JSON ), contentid NUMBER );
    
    INSERT INTO bodycontent ( body, contentid ) VALUES (
      '{"sections":[
         {"capsules":[{"timer":{"seconds":0}},{"timer":{"seconds":1}},{"timer":{"seconds":2}}]},
         {"capsules":[{"timer":{"seconds":3}},{"timer":{"seconds":4}},{"timer":{"seconds":5}}]},
         {"capsules":[{"timer":{"seconds":6}},{"timer":{"seconds":7}},{"timer":{"seconds":8}}]}]}',
      1081438
    );
    

    输出:

    0
    4
    

    或者,您可以只使用查询:

    SELECT section_index, capsule_index, time
    FROM   bodycontent b
           CROSS APPLY
           JSON_TABLE(
             b.body,
             '$.sections[*]'
             COLUMNS (
               section_index FOR ORDINALITY,
               NESTED PATH '$.capsules[*]'
                 COLUMNS (
                   capsule_index FOR ORDINALITY,
                   time NUMBER(11,0) PATH '$.timer.seconds'
                 )
               )
           ) j
    WHERE  ( j.section_index, j.capsule_index) IN ( (1,1), (2,2) )
    AND    b.contentid=1081438;
    

    哪些输出:

    SECTION_INDEX | CAPSULE_INDEX |时间 ------------: | ------------: | ---: 1 | 1 | 0 2 | 2 | 4

    (注意:FOR ORDINALITY 中的索引比 JSON 路径中的数组索引高 1。)

    db小提琴here

    【讨论】:

      【解决方案2】:

      您需要连接 json 路径中的变量:

      JSON_VALUE(body, '$.sections[' || to_char(i) || '].capsules[0].timer.seconds')
      

      我真的不明白你的问题与触发器有什么关系。

      【讨论】:

      • 首先,感谢您的回答。更新表数据时,我们正在创建一个触发器以将 JSON 数据存储在其他表中。但是如果你按照你告诉我的去做,就会出现以下错误。 [ORA-00907: 缺少右括号] 我应该如何修复它?
      • 不太一样。路径必须是文本文字。解决方案是动态 SQL。我刚刚写了一个答案来说明如何。
      【解决方案3】:

      所以,问题是您想要遍历索引(沿对角线穿过数组数组,只拾取两个元素) - 但 JSON_* 函数不能将变量用作数组索引 - 它们需要硬编码索引。

      PL/SQL 对此有一个答案 - 本机动态 SQL,如下所示。

      但是,请注意,这种方法会在同一个文档上重复调用JSON_VALUE()。根据实际要求(我假设您的问题仅用于说明)和文档的大小,单次调用JSON_TABLE() 可能更有效,如 MT0 的回答所示。如果实际上您确实只是从一个非常大的文档中提取两个标量值,那么对JSON_VALUE() 的两次调用可能是合理的,尤其是当文档比此处显示的大得多时;但是,如果您要从不太复杂的文档中提取许多标量值,那么对 JSON_TABLE() 的一次调用可能会更好,即使最终您没有使用它产生的所有数据。

      无论如何 - 作为原生动态 SQL 的说明,这里是替代解决方案(使用 MT0 的表):

      declare
        v_time number(11, 0);
      begin
        for i in 0..1 loop
          execute immediate q'#
          select json_value(body, '$.sections[#' || i ||
                            q'#].capsules[#' || i || q'#].timer.seconds')
          from   bodycontent
          where  contentid = 1081438#'
          into v_time;
          dbms_output.put_line(v_time);
        end loop;
      end;
      /
      
      
      0
      4
      
      PL/SQL procedure successfully completed.
      

      【讨论】:

        【解决方案4】:

        你可以看下面的例子:

        只需在您的控制台中点击此查询并尝试了解实现。

        SELECT JSON_VALUE('{
          "increment_id": "2500000043",
          "item_id": "845768",
          "options": [
            {
              "firstname": "Kevin"
            },
            {
              "firstname": "Okay"
            },
            {
              "lastname": "Test"
            }
          ]
        }', '$.options[0].firstname') AS value
          FROM DUAL;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-09-27
          • 2017-12-25
          • 1970-01-01
          • 1970-01-01
          • 2017-07-05
          • 1970-01-01
          • 2019-10-23
          • 2020-07-15
          相关资源
          最近更新 更多