本章讲解如何在 Oracle APEX 中装载来自 Excel、CSV、JSON、XML 和 ZIP 压缩包的外部数据。核心思路是先用 Data Load Definition 描述外部文件与目标表或集合之间的映射,再通过向导生成的 Data Loading 页面、原生页面处理或 APEX_DATA_LOADING 与 APEX_DATA_PARSER API 完成上传、预览、校验和装载。
17 装载外部数据#
在 APEX 中,外部数据装载不是单纯把文件内容插入数据库。一个可靠的装载流程通常要回答四个问题:文件是什么格式、字段如何映射到目标对象、用户在提交前能否预览结果、出错时如何定位到具体文件和行。APEX 对这些问题提供了两条路线:声明式配置和编程式处理。
- 声明式路线:创建 Data Load Definition,再用原生 Data Loading 页面处理完成装载。
- 编程式路线:直接调用
APEX_DATA_LOADING.LOAD_DATA、APEX_DATA_PARSER.PARSE和APEX_ZIP,把文件识别、预览、装载、统计和错误处理放进自定义 PL/SQL。 - 组合路线:用 Data Load Definition 保存稳定的文件配置文件,用
APEX_DATA_PARSER.PARSE做预览或自定义处理。
学习前提#
- 已有可运行的 Woods HR 示例应用,或等价的 APEX 应用与员工目标表。
- 目标表类似
EBA_DEMO_EMP,可以接收员工编号、姓名、职位、经理、入职日期、薪资、佣金和部门编号。 - 你能进入 App Builder、Shared Components、页面设计器和运行时页面。
来源:Oracle APEX 26.1 官方文档:Loading External Data
17.1 了解外部数据示例#
Woods HR 应用中的 HR 代表需要从外部文件导入员工数据。最常见的是 Excel 文件;第一行是列标题,后续行是员工记录。示例列包括 Employee Number、Last Name、Job Title、Manager ID、Hire Date、Salary、Commission 和 Department No。
同一类业务数据也可能来自 CSV、JSON 或 XML。字段名不一定一致,例如 CSV 可能使用 WORKER_NO、LAST_NAME、POSITION,JSON 可能使用 employeeId、fullName、positionTitle,XML 可能使用 STAFF-ID、SURNAME、ROLE。因此,本章的重点不是文件扩展名,而是把不同来源的字段统一映射到应用自己的员工表结构。
CSV 示例#
WORKER_NO,LAST_NAME,POSITION,BOSS_NO,ENTRY_DATE,PAY_RATE,BONUS_AMOUNT,SECTION_NO
8001,HOPPER,CLERK,7902,2025-03-14T00:00:00,900,,20
8002,CURIE,SALESMAN,7698,2025-11-05T00:00:00,1350,1200,30
JSON 示例#
{
"items": [
{
"employeeId": 8003,
"fullName": "GALLO",
"positionTitle": "MANAGER",
"reportsTo": 7839,
"startDate": "2025-04-22",
"salaryAmount": 2450,
"commissionValue": "",
"departmentCode": 10
}
]
}
XML 示例#
<ROWSET>
<ROW>
<STAFF-ID>8005</STAFF-ID>
<SURNAME>MENDEL</SURNAME>
<ROLE>ANALYST</ROLE>
<JOIN-DATE>2025-02-11T00:00:00</JOIN-DATE>
<BASE-PAY>3200</BASE-PAY>
<DIVISION>10</DIVISION>
</ROW>
</ROWSET>
操作与验收#
- 位置:准备本地样例文件,并确认目标表或集合中有对应字段。
- 动作:比较 Excel、CSV、JSON、XML 中代表同一业务含义的字段。
- 检查点:能列出源字段到目标字段的映射表,例如
WORKER_NO、employeeId、STAFF-ID都映射到员工编号。 - 预期结果:后续创建 Data Load Definition 时不会只依赖源文件列名,而会明确选择目标列。
来源:Oracle APEX 26.1 官方文档:Exploring External Data Examples
17.2 创建数据装载定义#
Data Load Definition 是 APEX 中描述外部文件结构和目标对象映射的共享组件。进入 Shared Components 后,通过创建向导选择目标类型、目标对象和样例文件。示例中创建的定义名为 Load Employees from Excel,目标是 EBA_DEMO_EMP 表。
向导第二步上传样例文件。样例可以是 Excel、CSV、JSON 或 XML。若 Excel 工作簿包含多个工作表,向导会提供工作表选择列表,要求你选择实际要分析和装载的工作表。APEX 随后分析文件内容,推断列名、数据类型和需要的格式掩码。
在 Map Columns 步骤中,左侧是 APEX 发现的源列,右侧 Map To 列用于选择目标列。不需要装载的源列应保持 Map To 为空。
完成映射后,进入 Preview 标签页验证解析结果。确认字段、日期、数值和空值都符合预期后,再创建数据装载定义。
操作与验收#
- 位置:Shared Components 中的 Data Load Definitions。
- 动作:创建 Load Employees from Excel,上传 Excel 样例文件,将员工字段映射到
EBA_DEMO_EMP。 - 检查点:预览页能显示待装载数据,日期和数字没有被错误识别为普通文本。
- 预期结果:生成一个可复用的数据装载定义,后续页面和 API 都能按其文件配置文件处理 Excel 数据。
来源:Oracle APEX 26.1 官方文档:Creating a Data Load Definition
17.3 扩充数据装载配置文件列#
数据装载定义不仅可以映射源列,还可以在 Data Profile 中改造列。示例 Excel 中的员工姓氏是混合大小写,例如 Faraday 和 Noether,而 Woods HR 应用期望目标列 ENAME 使用大写。
处理办法是编辑 Load Employees from Excel 定义,打开其 Data Profile,先把原来的 ENAME 配置文件列重命名为 ORIG_ENAME。这样可以保留原始输入值,方便后续表达式引用。
ENAME 数据配置文件列重命名为 ORIG_ENAME。然后在 Data Profile 中新增一个名为 ENAME 的列,类型选择 SQL Expression,数据类型选择 VARCHAR2。表达式把源文件中的 ORIG_ENAME 转成大写,最终写入目标表的 ENAME。
upper( ORIG_ENAME )
同一机制也可用于固定值或应用级上下文值。例如表达式可以调用 V('G_APP_USER_EMPNO'),把全局应用项的值写入目标列,用于补充上传人、来源系统或业务批次。
ENAME 添加 SQL Expression 数据配置文件列。操作与验收#
- 位置:Shared Components -> Data Load Definitions -> Data Profile。
- 动作:保留原始姓名列,新增表达式列生成规范化后的目标值。
- 检查点:预览中能同时区分原始输入和最终装载值。
- 预期结果:运行装载后,员工目录中的姓名显示为大写,同时装载定义仍能说明数据是如何从源字段转换来的。
来源:Oracle APEX 26.1 官方文档:Augmenting Data Load Profile Columns
17.4 生成并使用数据装载页面#
创建数据装载定义后,可以用 Create Page Wizard 生成一个 Data Loading 页面,让最终用户选择文件、上传文件、预览解析结果并执行装载。向导生成的页面把文件上传项、校验、工作表选择、预览区域和原生数据装载页面处理组合在一起。
来源:Oracle APEX 26.1 官方文档:Generating and Using a Data Loading Page
17.4.1 创建数据装载页面#
在 Create Page Wizard 中选择 Data Loading。向导会要求选择一个已有数据装载定义,例如 Load Employees from Excel。本例保留默认的 Upload Data From = File,表示用户从本地选择文件上传;APEX 也支持创建让用户粘贴数据内容的页面。
操作与验收#
- 位置:App Builder -> Create Page -> Data Loading。
- 动作:选择 Load Employees from Excel 并创建页面。
- 检查点:页面设计器中出现文件上传项、预览区域和装载按钮。
- 预期结果:页面可以作为 HR 用户的导入入口,而不需要用户进入 Builder。
来源:Oracle APEX 26.1 官方文档:Creating a Data Loading Page
17.4.2 使用数据装载页面#
运行生成的页面后,用户首先看到一个文件拖放区域。选择或拖入 emp.xlsx 后,页面立即上传文件并显示预览。确认数据无误后,点击 Load Data 执行装载。
装载完成后,页面显示处理行数。示例中,HR 代表 Susan 打开员工目录,能看到新导入的 FARADAY 和 NOETHER,说明 17.3 中的 SQL Expression 配置文件列已经把姓名转换为大写。
操作与验收#
- 位置:运行生成的 Load Employees from Excel 页面。
- 动作:上传 Excel 文件,预览后执行 Load Data。
- 检查点:页面显示成功消息,且员工目录能查到新员工。
- 预期结果:最终数据符合目标表规范,姓名大写转换已生效。
来源:Oracle APEX 26.1 官方文档:Using a Data Loading Page
17.4.3 理解数据装载页面#
向导生成的数据装载页面通常包含五类功能:文件上传页面项、文件类型校验、多工作表选择器、数据预览区域,以及原生 Data Loading 页面处理。理解这些组成部分后,就能把生成页面改造成更贴合业务的导入体验。
来源:Oracle APEX 26.1 官方文档:Understanding Data Loading Pages
17.4.3.1 指定并上传文件#
生成的 Load Employees from Excel 页面包含 P32_FILE 文件上传项,显示方式为 Block Dropzone。上传文件暂存在 APEX_APPLICATION_TEMP_FILES 表中,默认一次只上传一个文件。
Upload a File 动态操作监听 P32_FILE 的 Change 事件。用户选择文件后,动态操作立即执行原生 Submit Page 动作,把文件提交到服务器。
提交后,一个 After Submit 计算会读取 APEX_APPLICATION_TEMP_FILES.FILENAME,并把原始文件名填入只读显示项 P32_FILE_NAME。由于页面没有分支跳转,处理完成后会重新渲染当前页面。
操作与验收#
- 位置:页面设计器中的
P32_FILE、动态操作和 After Submit 计算。 - 动作:确认文件项的存储目标是
APEX_APPLICATION_TEMP_FILES,并确认选择文件后会提交页面。 - 检查点:上传后
P32_FILE_NAME显示用户选择的文件名。 - 预期结果:文件已到达服务器临时表,后续校验和预览可以使用同一个临时文件标识。
来源:Oracle APEX 26.1 官方文档:Specifying the File and Uploading It
17.4.3.2 校验上传文件类型#
生成页面会在 P32_FILE 文件上传项上配置校验,只允许预期的文件类型提交。示例使用 APEX_DATA_PARSER.ASSERT_FILE_TYPE 检查临时文件是否为 Excel 工作簿;校验失败时清空 P32_FILE 并返回失败。
if apex_data_parser.assert_file_type(
p_file_name => :P32_FILE_NAME,
p_file_type => apex_data_parser.c_file_type_xlsx )
then
return true;
else
:P32_FILE := null;
return false;
end if;
操作与验收#
- 位置:
P32_FILE页面项上的验证。 - 动作:使用
APEX_DATA_PARSER.C_FILE_TYPE_XLSX限制 Excel 文件。 - 检查点:上传非 Excel 文件时验证失败,并且文件项被清空。
- 预期结果:装载处理不会拿错误文件类型继续解析,用户需要重新选择合法文件。
来源:Oracle APEX 26.1 官方文档:Validating the Uploaded File Type
17.4.3.3 让用户选择工作表#
当 Excel 文件包含多个工作表时,页面项 P32_XLSX_WORKSHEET 才需要显示。它的服务端条件使用 APEX_DATA_PARSER.GET_XLSX_WORKSHEETS 读取上传文件的工作表列表,只有工作表数量大于 1 时才返回 true。
declare
l_sheet_count number;
begin
select count(*)
into l_sheet_count
from apex_application_temp_files f,
table(apex_data_parser.get_xlsx_worksheets(
p_content => f.blob_content)) p
where f.name = :P32_FILE;
return (l_sheet_count > 1);
exception
when others then
return false;
end;
选择列表的 SQL 同样从临时文件中读取工作表名称,向用户显示可读名称,并把实际工作表文件名作为返回值。
select p.sheet_display_name,
p.sheet_file_name
from apex_application_temp_files f,
table(apex_data_parser.get_xlsx_worksheets(
p_content => f.blob_content)) p
where f.name = :P32_FILE
用户切换工作表后,页面通过动态操作提交。重新渲染后,预览区域会使用新选择的工作表重新解析数据。
操作与验收#
- 位置:
P32_XLSX_WORKSHEET选择列表及其动态操作。 - 动作:上传多工作表 Excel,确认选择列表出现;上传单工作表 Excel,确认选择列表隐藏。
- 检查点:切换工作表后页面重新提交,预览内容随之变化。
- 预期结果:用户明确选择要装载的工作表,避免误装载其他工作表的数据。
来源:Oracle APEX 26.1 官方文档:Letting User Select Worksheet
17.4.3.4 装载前预览外部数据#
Preview 区域是一个 Classic Report。它有服务端条件:只有 P32_FILE 不为空,也就是用户已经上传文件后才显示。报表查询调用 APEX_DATA_PARSER.PARSE,并通过 APEX_DATA_LOADING.GET_FILE_PROFILE 取得静态 ID 为 load_employees_from_excel 的文件配置文件。为了避免预览过大,示例限制最多显示 100 行。
select p.line_number,
p.col001, p.col002, p.col003, p.col004, p.col005,
p.col006, p.col007, p.col008, p.col009, p.col010
from apex_application_temp_files f,
table(apex_data_parser.parse(
p_content => f.blob_content,
p_file_name => f.filename,
p_xlsx_sheet_name => case
when :P32_XLSX_WORKSHEET is not null
then :P32_XLSX_WORKSHEET
end,
p_file_profile => apex_data_loading.get_file_profile(
p_static_id => 'load_employees_from_excel'),
p_max_rows => 100)) p
where f.name = :P32_FILE
APEX_DATA_PARSER.PARSE 预览待装载数据。预览区域的表头类型设置为 None。为了让用户看到的顺序与文件中的顺序一致,LINE_NUMBER 列的默认排序序号应为 1,排序方向为升序。
LINE_NUMBER 升序显示。操作与验收#
- 位置:Preview 经典报表区域及
LINE_NUMBER列属性。 - 动作:确认报表只在上传后显示,并使用数据装载定义的文件配置文件解析。
- 检查点:预览行数受控,顺序与源文件一致。
- 预期结果:用户可以在真正装载前发现格式、列映射或工作表选择错误。
来源:Oracle APEX 26.1 官方文档:Previewing External Data Before Loading
17.4.3.5 使用原生页面处理装载数据#
用户确认预览后点击 Load 按钮,页面提交并执行 Load Data 页面处理。该处理的服务端条件确保它只在按下 LOAD 按钮时运行。处理类型是原生 Data Loading,数据装载定义设置为 Load Employees from Excel。
数据来源可以是文本区域、返回 CLOB 或 BLOB 的 SQL 查询,也可以是文件上传项的临时文件。本例使用 P32_FILE 文件上传项中的临时文件,并把 P32_XLSX_WORKSHEET 的值传给工作表名称设置。若页面处理配置了成功消息,该消息优先显示;否则原生处理会显示默认的装载行数消息。
操作与验收#
- 位置:页面处理 Load Data。
- 动作:确认处理类型、数据装载定义、文件来源和工作表项配置。
- 检查点:只有按下 Load 才执行装载,单纯上传和预览不会写入目标表。
- 预期结果:用户确认预览后,原生页面处理按数据装载定义写入目标表,并反馈处理结果。
来源:Oracle APEX 26.1 官方文档:Loading Data with Native Page Process
17.5 不使用数据装载定义解析数据#
如果外部数据结构是稳定的,引用已有 Data Load Definition 是最有效的做法。但在一次性导入、探索性预览或文件结构运行时才确定的场景中,也可以直接调用 APEX_DATA_PARSER.PARSE,让 APEX 在运行时推断文件结构。它支持 CSV、XML、JSON 和 Excel,并以 C001 到 C300 的通用列返回数据。
直接解析后,可以调用 GET_COLUMNS 获取发现的列名和数据类型,调用 GET_FILE_PROFILE 取得 JSON 格式的文件配置文件。如果希望在 PL/SQL 记录结构中处理文件配置文件,可以把 JSON 传给 JSON_TO_PROFILE,得到 T_FILE_PROFILE 记录。
操作与验收#
- 位置:自定义 PL/SQL 处理、报表查询或预览逻辑。
- 动作:在不知道固定结构时调用
APEX_DATA_PARSER.PARSE,再读取发现的列信息。 - 检查点:能解释
C001到C300是解析器返回的通用列,而不是目标表列。 - 预期结果:应用可以预览或处理结构不固定的外部文件,但开发者需要自己完成列选择、类型转换、错误记录和最终 DML。
来源:Oracle APEX 26.1 官方文档:Parsing Data Without Data Load Definition
17.6 装载多个文件与 ZIP#
HR 代表可能一次收到多个文件,格式包括 Excel、CSV、JSON、XML,甚至多个文件打包成一个 ZIP。为这种需求设计页面时,应把单文件向导能力扩展为批处理流程:每种源格式有自己的数据装载定义,文件上传项允许多文件,自定义 PL/SQL 根据扩展名或 MIME 类型选择正确的装载定义,并在遇到 ZIP 时逐个处理压缩包内的文件。
来源:Oracle APEX 26.1 官方文档:Loading Multiple Files Including ZIPs
17.6.1 添加 XML、CSV、JSON 数据装载定义#
为了让不同文件格式都装入同一个 EBA_DEMO_EMP 目标表,需要分别为 XML、CSV 和 JSON 再运行数据装载定义向导。示例中新增三个共享组件,其静态 ID 分别是:
- Load Employees from XML:
load_employees_from_xml - Load Employees from CSV:
load_employees_from_csv - Load Employees from JSON:
load_employees_from_json
虽然三类文件使用不同字段命名,但最终目标列一致。因此每个定义中的 Map To 配置都应指向同一组员工目标列。
操作与验收#
- 位置:Shared Components -> Data Load Definitions。
- 动作:为 XML、CSV、JSON 各创建一个定义,并设置可预测的静态 ID。
- 检查点:所有格式最终映射到同一个员工目标表结构。
- 预期结果:后续自定义 PL/SQL 可以通过文件类型拼出静态 ID,并调用统一的装载 API。
来源:Oracle APEX 26.1 官方文档:Adding XML, CSV, JSON Data Load Definitions
17.6.2 设置文件上传项以处理多个文件#
批量装载页面使用 P33_FILE 文件上传项,并启用 Allow Multiple Files。显示方式可以设置为 Block Dropzone,并用自定义标题和描述提示用户可以一次选择多个文件。上传文件保存在 APEX_APPLICATION_TEMP_FILES,示例将清理时机设置为 End of Request,表示提交请求处理完成后删除临时文件。
页面还使用四个隐藏项保存处理结果,类似页面级局部变量:
P33_FILE_COUNT:已处理文件数。P33_PROCESSED_ROWS:已处理员工行数。P33_ERROR_ROWS:错误行数。P33_SUCCESS_MESSAGE:自定义成功消息。
操作与验收#
- 位置:批量装载页面的
P33_FILE和隐藏项。 - 动作:启用多文件上传,设置请求结束时清理临时文件。
- 检查点:提交时
P33_FILE包含多个临时文件名,处理统计能回写到隐藏项。 - 预期结果:页面可以一次接收多种格式文件,并在同一次请求中完成处理和反馈。
来源:Oracle APEX 26.1 官方文档:Setting File Upload to Handle Multiple Files
17.6.3 处理多个已上传文件#
用户点击 Load 后,页面提交并执行 Load Employees from Files 页面处理。该处理类型是 Invoke API,调用包 EBA_DEMO_WOODSHR_LOAD 中的 EMPLOYEES_FROM_FILES 过程。输入参数 p_file_names 来自 P33_FILE,三个输出参数分别回写到 P33_FILE_COUNT、P33_PROCESSED_ROWS 和 P33_ERROR_ROWS。
应用定义两个可翻译文本消息,用于根据文件数量生成不同的成功提示。随后的 Execute Code 页面处理调用 APEX_LANG.GET_MESSAGE,把文件数和已处理行数填入消息占位符,并写入 P33_SUCCESS_MESSAGE。
:P33_SUCCESS_MESSAGE :=
apex_lang.get_message(
p_name => case
when :P33_FILE_COUNT = 1
then 'ONE_FILE_ROWS_PROCESSED'
else 'MANY_FILES_ROWS_PROCESSED'
end,
p_params => case
when :P33_FILE_COUNT = 1
then apex_t_varchar2('0', :P33_PROCESSED_ROWS)
else apex_t_varchar2('0', :P33_FILE_COUNT,
'1', :P33_PROCESSED_ROWS)
end);
EMPLOYEES_FROM_FILES 的职责是遍历 APEX_APPLICATION_TEMP_FILES 中本次上传的所有文件,并对每个文件调用辅助过程。辅助过程根据文件扩展名或 MIME 类型决定要使用的装载定义后缀:csv、json、xml、excel 或 zip。普通文件调用 APEX_DATA_LOADING.LOAD_DATA;ZIP 文件调用 APEX_ZIP.GET_FILES 取得压缩包内文件列表,再递归使用同一套文件装载逻辑。
-- 核心结构示意,保留与官方示例相同的处理边界
for uploaded_file in (
select blob_content, filename, mime_type
from apex_application_temp_files
where name in (select column_value
from apex_string.split(p_file_names, ':'))
) loop
data_load_for_file(
p_content => uploaded_file.blob_content,
p_filename => uploaded_file.filename,
p_mime_type => uploaded_file.mime_type,
p_file_count => p_file_count,
p_processed_rows => p_processed_rows,
p_error_rows => p_error_rows);
end loop;
l_data_load_def_suffix :=
case
when extension in ('txt','csv') then 'csv'
when extension = 'json' then 'json'
when extension = 'xml' then 'xml'
when extension in ('xls','xlsx') then 'excel'
when extension = 'zip' then 'zip'
end;
if l_data_load_def_suffix = 'zip' then
data_load_from_zip(...);
elsif l_data_load_def_suffix is not null then
l_result := apex_data_loading.load_data(
p_static_id => 'load_employees_from_' || l_data_load_def_suffix,
p_data_to_load => p_content);
end if;
操作与验收#
- 位置:Invoke API 页面处理、隐藏项、包
EBA_DEMO_WOODSHR_LOAD。 - 动作:把上传文件名传入 PL/SQL,遍历临时文件,根据格式调用不同数据装载定义。
- 检查点:未知文件类型不会被误装载;ZIP 内文件会被逐个识别并处理。
- 预期结果:页面可以给出文件数、成功行数和错误行数,并支持本地化成功消息。
来源:Oracle APEX 26.1 官方文档:Processing Multiple Uploaded Files
17.6.4 上传多个数据装载文件#
完成批量页面配置后,HR 代表 Susan 可以在 Load Employees 页面一次选择 Excel、CSV、JSON 和 XML 文件,然后点击 Load 统一装载。
自定义成功消息会确认四个文件已装载,并报告新增员工总数。若用户提交的是普通文件与 ZIP 文件的混合,逻辑同样适用:ZIP 中的 XML、CSV、JSON 和 Excel 文件会按各自数据装载定义处理。
操作与验收#
- 位置:运行时 Load Employees 批量装载页面。
- 动作:一次上传 Excel、CSV、JSON、XML,另测一次包含 ZIP 的组合。
- 检查点:成功消息中的文件数和新增员工数与输入文件一致。
- 预期结果:不同格式的员工数据都按对应文件配置文件写入目标表,ZIP 内文件也能被处理。