真正可用的自定义报表生成需按目标分路径:HTML用字符串拼接+Chart.js、PDF用UTL_PDF、XLSX用as_xlsx包;中文需转码,大结果集须流式输出,文件落地要注意并发与权限。

不能靠 UTL_FILE 直接写 Excel 或 PDF 当“报表”,它只输出纯文本,不是真正的格式化报表文件;真正可用的自定义报表生成,得按输出目标分路径:导 HTML 图表用字符串拼接 + 前端库、导 PDF 用 UTL_PDF、导真实 .xlsx 必须引入 as_xlsx 包。
用 PL/SQL 拼 HTML + Chart.js 生成可视化报表
这是最轻量、免安装、适合运维看板或内部监控页的方式。核心是把查询结果转成 JSON 数组,再嵌入 HTML 模板里调用 Chart.js 渲染。
- 中文字段必须用
CONVERT(col, 'AL32UTF8', 'ZHS16GBK')转码,否则浏览器显示乱码 -
HTP.PRN输出时要先调用OWA_UTIL.MIME_HEADER('text/html'),否则浏览器当下载处理 - 大结果集别一次性
BULK COLLECT到数组——容易 ORA-04030;改用游标循环 +HTP.PRN流式输出更稳 - Chart.js 版本建议锁定 v3.9.1(CDN 地址:
https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js),v4+ 需要 ES Module 环境,PL/SQL 无法支持
用 UTL_PDF 生成结构化 PDF 报表
UTL_PDF 是 Oracle 原生包,不依赖外部 Java,但要求 Oracle 12cR2 及以上版本,且必须提前运行安装脚本启用。
- 文档生命周期必须严格配对:
UTL_PDF.FEGIN→ 多个UTL_PDF.ADD_PAGE→UTL_PDF.FEND,漏掉FEND会导致 BLOB 残缺、PDF 打不开 - 中文字体要用
UTL_PDF.FONT('SIMSUN.TTC', 'Bold')这类系统已安装的 TrueType 字体路径,不能用 Arial Unicode MS 等未注册字体 - 表格画线靠
UTL_PDF.LINE手动控制坐标,没有自动列宽计算;列宽需按字符数 × 单字宽度预估(如宋体 12pt 下约 8px/字) - 图像插入前必须先用
UTL_RAW.CAST_TO_RAW将 BLOB 转为 RAW,否则报 ORA-29283
用 as_xlsx 包生成真实 .xlsx 文件(非 CSV)
这是唯一能在纯 PL/SQL 中产出标准 Office Open XML 格式 Excel 的方案,as_xlsx.query2sheet_g 最方便,但有硬性限制。
- 动态 SQL 必须拼完整字符串传入
p_sql,不支持绑定变量——例如写成'SELECT * FROM ' || p_table_name || ' WHERE dt = ''' || p_date || '''' - 超过 5 万行请弃用
query2sheet_g,改用as_xlsx.new_sheet+ 游标循环 +as_xlsx.cell,否则内存溢出概率极高 - 日期类型字段会自动转成 Excel 序列号(如 45201 表示 2023-10-01),需在 SQL 层用
TO_CHAR(dt, 'yyyy-mm-dd')强制转字符串才能保持可读 - 样式只能通过
as_xlsx.set_column_width和as_xlsx.merge_cells控制,不支持字体颜色、边框线型等细粒度设置
文件落地与并发安全陷阱
无论生成 HTML、PDF 还是 XLSX,只要写到服务器文件系统,就绕不开 UTL_FILE 的权限和并发问题。
-
CREATE DIRECTORY创建的逻辑目录(如DIR_REPORTS)路径必须是数据库服务器上的绝对路径,且 Oracle OS 用户对该路径有rwx权限 - 文件名带时间戳不够安全:
TO_CHAR(SYSDATE, 'yyyymmddhh24miss')在高并发下极易重复;务必加随机后缀,例如|| '_' || DBMS_RANDOM.STRING('A', 4) - 写完文件后记得调用
UTL_FILE.FCLOSE,否则下次FOPEN同名文件会报 ORA-29285(尤其在 Windows 上更敏感) - 不要在存储过程中直接
COMMIT;文件写失败时事务应能回滚,文件操作属于外部副作用,需单独捕获异常并清理
真正卡住人的往往不是语法,而是字符集转换时机、内存阈值判断、以及并发写同名文件时的静默失败——这些点不提前踩一遍,上线后问题只会出现在凌晨三点的告警电话里。


















