Oracle 12.1.0.2 中的批量更新?

Posted

技术标签:

【中文标题】Oracle 12.1.0.2 中的批量更新?【英文标题】:Bulk Update in Oracle 12.1.0.2? 【发布时间】:2018-10-18 06:32:13 【问题描述】:

我目前正在处理一项任务,并且需要通过从 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;

我应该使用二维数组并使用它来批量更新还是可以采用其他方法?

添加了示例 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"
    ]
  ]

【问题讨论】:

从哪里获取 json 以及如何将其存储到集合中? 我从 Web 服务响应中获取 json,并将该输出存储在 CLOB 中。我想要更好的方法或我使用的方法好的建议? 你能展示你的示例 json 吗?请通过编辑您的问题来添加它。 【参考方案1】:

假设你的桌子是这样的:

  create table table_name 
  ( 
     id number(12) primary key,
     route_sequence number(12),
     updated_by varchar2(30),
     updated_on timestamp(9)  
  )  

而且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,
        ]
  

您可以使用“JSON_TABLE” sql 运算符(oracle 12 的新功能 - 请参阅 https://docs.oracle.com/database/121/SQLRF/functions092.htm#SQLRF56973)直接在 SQL 中查询 json 数据...然后您可以利用它,在“合并”中使用这样的查询"声明:

这条 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                  

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

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

 '$."activities"[*]'

与此一致:

 '$."plan"[0]."activities"[*]'

如果“计划”数组项包含多个元素,事情可能会变得更复杂,但它仍然可以完成。


编辑2:如何处理嵌套对象(即:当“plan”包含多个对象时怎么办

假设要处理的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"
                       
                   ]
               
          ]
    '

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

如果您对阅读 vehicle_id 字段不感兴趣,并且想要查看所有活动详细信息的平面视图(无论哪个“计划”对象包含它们,您都可以从中更改根对象选择器字符串

 '$."plan"[0]."activities"[*]'

到这里:

 '$."plan"[*]."activities"[*]'

所以,这个查询:

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

将遍历所有计划对象的所有“活动”对象,但它只会返回“task_id”和“sequence”列。

如果您还希望在所有行上重复相应的车辆 id 列,则必须使用此表达式提升根选择器的级别

'$."plan"[*]'

并且在“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'
                )
        )
   ) 

【讨论】:

请注意,我在这里作为文字常量传递的 json 文本也可以作为 clob 值从数据库中读取 我只是来这里发布一个类似的答案并看到你的。干得好 +1。 @CarloSirna 感谢您提供如此快速且有效的答案。真的行。最后一个问题,可以做什么是plan数组包含超过1个元素?另外,当我检查我的方法和你的方法任务时,只需 1 秒。那么这个答案会帮助我提高 2000 到 4000 条记录的性能吗? @KinjanBhavsar:我刚刚尝试创建一个包含超过 16,000 个“活动”项目的 clob 字段,我使用该字段作为 json 的源运行我的合并语句,它需要 0.74 秒在我蹩脚的开发服务器上运行。我必须进行一些试验才能使其与更多“计划”元素一起使用……让我试试…… 好的。你认为是因为我的 json 第一个活动对象,它需要时间吗?第一个对象只有序列而不是task_id,你可能已经注意到我的代码也出于同样的原因从2开始循环到(count -1)。

以上是关于Oracle 12.1.0.2 中的批量更新?的主要内容,如果未能解决你的问题,请参考以下文章

PLSQL中批量更新数据

oracle数据库如何用update批量更新某列数据中的字段

oracle批量更新的问题

Mybatis在oracle批量更新

oracle 如何实现对单个表批量更新

oracle批量新增更新数据