Oracle 12.1.0.2 中的批量更新?
Bulk Update in Oracle 12.1.0.2?
我目前正在处理一项任务,需要通过读取 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"
}]
}]
}
假设你的table是这样的:
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 运算符直接在 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
编辑:现在您已经发布了实际的 json 示例:
要使我的示例适用于您的数据,您只需替换
'$."activities"[*]'
符合这个:
'$."plan"[0]."activities"[*]'
如果 "plan" 数组项包含多个元素,事情会变得更复杂,但仍然可以完成。
编辑 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" 对象包含它们,您可以只更改根对象来自 this
的选择器字符串
'$."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'
)
)
将遍历所有计划对象的所有 "activities" 个对象,但它 return 你只会遍历 "task_id" 和 "sequence" 列。
如果您还想在所有行上重复相应的车辆 ID 列,则必须使用此表达式提高根选择器的水平
'$."plan"[*]'
并且在 "columnns" 子句中,您可以使用 "nested path" 语法表示您还想在线扩展子对象的列:
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 中的值来更新大约 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"
}]
}]
}
假设你的table是这样的:
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 运算符直接在 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
编辑:现在您已经发布了实际的 json 示例:
要使我的示例适用于您的数据,您只需替换
'$."activities"[*]'
符合这个:
'$."plan"[0]."activities"[*]'
如果 "plan" 数组项包含多个元素,事情会变得更复杂,但仍然可以完成。
编辑 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" 对象包含它们,您可以只更改根对象来自 this
的选择器字符串 '$."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'
)
)
将遍历所有计划对象的所有 "activities" 个对象,但它 return 你只会遍历 "task_id" 和 "sequence" 列。
如果您还想在所有行上重复相应的车辆 ID 列,则必须使用此表达式提高根选择器的水平
'$."plan"[*]'
并且在 "columnns" 子句中,您可以使用 "nested path" 语法表示您还想在线扩展子对象的列:
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'
)
)
)