Oracle 12.1.0.2中的批量更新?

Kin*_*sar 2 oracle plsql oracle12c bulkupdate

我目前正在处理一项任务,并要求通过读取JSON中的值来更新大约2000到4000条记录.我优化了JSON部分但是目前,我正在逐个更新每个记录.有人建议使用单一查询更新所有2000到4000条记录的最佳方法,而不是运行2000至4000次吗?这是我的示例代码

    APEX_JSON.PARSE(V_OUTPUT_DATA); 
plan_count := apex_json.get_count('plan'); 
IF plan_count > 0 THEN 
    FOR I in 1..plan_count LOOP 
        activities_count := APEX_JSON.get_count(p_path => 'plan['||i||'].activities'); 
        IF activities_count > 0 THEN 
            FOR j in 2..(activities_count-1) LOOP 
                V_TASK_ID := APEX_JSON.get_varchar2(p_path => 'plan['||i||'].activities['||j||'].task_id'); 
                V_SEQ := APEX_JSON.get_number(p_path => 'plan['||i||'].activities['||j||'].sequence');
                UPDATE TABLE_NAME 
                SET ROUTE_SEQUENCE = V_SEQ, UPDATED_BY = 'SYSTEM',UPDATED_ON = SYSTIMESTAMP 
                WHERE TASK_ID = V_TASK_ID; 
            END LOOP; 
            COMMIT; 
        END IF; 
    END LOOP;       
END IF;
Run Code Online (Sandbox Code Playgroud)

我应该使用2D阵列并使用它进行批量更新还是可以遵循其他方法?

已添加示例JSON

{
"plan": [{
    "vehicle_id": "vehicle_1",
    "activities": [{
        "sequence": 0,
        "timestamp": "2017-11-10T09:48:19Z",
        "location_id": "depot"
    },
    {
        "sequence": 1,
        "timestamp": "2017-11-10T09:50:07Z",
        "task_id": "465427",
        "location_id": "465427",
        "travel_distance": 1099,
        "travel_duration": "00:01:48"
    },
    {
        "sequence": 2,
        "timestamp": "2017-11-10T09:50:10Z",
        "task_id": "443951",
        "location_id": "443951",
        "travel_distance": 26,
        "travel_duration": "00:00:03"
    },
    {
        "sequence": 3,
        "timestamp": "2017-11-10T09:50:25Z",
        "task_id": "165760",
        "location_id": "165760",
        "travel_distance": 152,
        "travel_duration": "00:00:15"
    },
    {
        "sequence": 4,
        "timestamp": "2017-11-10T09:51:34Z",
        "task_id": "459187",
        "location_id": "459187",
        "travel_distance": 705,
        "travel_duration": "00:01:09"
    }]
  }]
}
Run Code Online (Sandbox Code Playgroud)

Car*_*rna 5

假设你的桌子是这样的:

  create table table_name 
  ( 
     id number(12) primary key,
     route_sequence number(12),
     updated_by varchar2(30),
     updated_on timestamp(9)  
  )  
Run Code Online (Sandbox Code Playgroud)

并且json对象就像这样:

  {
       "activities": 
        [
            {"task_id": 1, "sequence" : 10},
            {"task_id": 2, "sequence" : 20},
            {"task_id": 3, "sequence" : 30},
            {"task_id": 4, "sequence" : 40},
            {"task_id": 5, "sequence" : 50},
        ]
  }
Run Code Online (Sandbox Code Playgroud)

您可以使用"JSON_TABLE"sql运算符直接在SQL中查询json数据(oracle 12新增 - 请参阅https://docs.oracle.com/database/121/SQLRF/functions092.htm#SQLRF56973)...然后你可以利用它,在"merge"语句中使用这样的查询:

这个单一的SQL语句可以满足您的需求:

 merge into table_name t
 using
 (
      select * 
      from JSON_TABLE(
              '{
                   "activities": 
                   [
                       {"task_id": 1, "sequence" : 10},
                       {"task_id": 2, "sequence" : 20},
                       {"task_id": 3, "sequence" : 30},
                       {"task_id": 4, "sequence" : 40},
                       {"task_id": 5, "sequence" : 50},
                   ]
              }', 
              '$."activities"[*]'

              COLUMNS(    
                       V_TASK_ID  NUMBER   PATH '$.task_id',
                       V_SEQ    NUMBER   PATH '$.sequence'
                  )
              )
 ) json_data
 on (json_data.v_task_id = t.id)
 when matched then 
    update set 
      ROUTE_SEQUENCE = V_SEQ,
      UPDATED_BY = 'SYSTEM',
      UPDATED_ON = SYSTIMESTAMP                  
Run Code Online (Sandbox Code Playgroud)

编辑:现在您已经发布了实际的json示例:

让我的示例使用您的数据,您只需要替换

 '$."activities"[*]'
Run Code Online (Sandbox Code Playgroud)

与这一行:

 '$."plan"[0]."activities"[*]'
Run Code Online (Sandbox Code Playgroud)

如果"plan"数组项包含多个元素,那么事情会变得更复杂,但仍然可以完成.


编辑2:如何处理嵌套对象(即:"计划"包含多个对象时要执行的操作

假设要处理的json字符串就是这个字符串

    '{
        "plan": 
         [
              {
                  "vehicle_id": "vehicle_1",
                  "activities": 
                   [
                       {
                           "sequence": 1,
                           "task_id": "465427"
                       },
                       {
                           "sequence": 2,
                           "task_id": "443951"
                       }
                   ]    
              }
              ,
              {
                  "vehicle_id": "vehicle_2",
                  "activities": 
                   [
                       {
                           "sequence": 3,
                           "task_id": "165760"
                       },
                       {
                           "sequence": 4,
                           "task_id": "459187"
                       }
                   ]
               }
          ]
    }'
Run Code Online (Sandbox Code Playgroud)

(我不会在我的例子中重复它:我会写的 在代码中

如果您对读取vehicle_id字段不感兴趣,并且想要查看所有活动详细信息(无论哪个"plan"对象包含它们),您只需更改根对象选择器字符串即可

 '$."plan"[0]."activities"[*]'
Run Code Online (Sandbox Code Playgroud)

对此:

 '$."plan"[*]."activities"[*]'
Run Code Online (Sandbox Code Playgroud)

所以,这个查询:

 select * 
 from JSON_TABLE
   (
       <json_string_here>,
       '$."plan"[*]."activities"[*]'
        COLUMNS(    
                V_TASK_ID  NUMBER   PATH '$.task_id',
                V_SEQ    NUMBER   PATH '$.sequence'
        )
   )
Run Code Online (Sandbox Code Playgroud)

将遍历所有计划对象的所有"活动"对象,但它将仅返回"task_id"和"sequence"列.

仅遍历叶子细节

如果你想要在所有行上重复相应的车辆id列,你必须使用这个表达式在你的根选择器上升级

'$."plan"[*]'
Run Code Online (Sandbox Code Playgroud)

在"columnns"子句中,您可以使用"嵌套路径"语法来表示您想要在线扩展子对象的列:

   select * 
   from JSON_TABLE
   (
        <json_string_here>,
        '$."plan"[*]'
        COLUMNS
        ( 
            VEHICLE  varchar2(20) PATH '$."vehicle_id"',
            NESTED PATH '$."activities"[*]'
               COLUMNS
               (
                     V_TASK_ID  NUMBER   PATH '$.task_id',
                     V_SEQ    NUMBER   PATH '$.sequence'
                )
        )
   ) 
Run Code Online (Sandbox Code Playgroud)

扩展子对象列