Skip to content

流程表单数据查询

RuoYi Office 扩展指南:使用 SQL 查询流程表单(NORMAL 类型)的单据数据。

1. 数据存储原理

1.1 两种表单类型对比

维度流程表单(NORMAL)业务表单(CUSTOM)
数据存储Flowable 流程变量表(ACT_HI_VARINST独立业务表(如 oa_seal_apply_bill
表单定义bpm_form 表(JSON)前端 Vue 组件
查询方式需特殊 SQL(EAV 行转列)标准 SQL

1.2 EAV 存储模型

流程表单采用 EAV 模型(Entity-Attribute-Value):每个表单字段是变量表中的一行记录,而不是传统业务表的一列。

提交流程时:

  1. 前端将 form-create 表单的所有字段值打包为 variables 对象
  2. 后端将 variables 传入 Flowable 引擎
  3. Flowable 将每个变量存为 ACT_HI_VARINST 表中的一行

1.3 涉及的数据库表

说明
ACT_HI_PROCINST历史流程实例
ACT_HI_VARINST历史流程变量(查单据数据的主要表
ACT_RU_VARIABLE运行时流程变量(仅审批中的流程)
bpm_form表单定义(fields 字段包含字段名→标题的映射)
bpm_process_definition_info流程定义扩展(关联表单 ID)

1.4 ACT_HI_VARINST 表结构

字段类型说明
ID_varchar(64)主键
PROC_INST_ID_varchar(64)流程实例 ID
TASK_ID_varchar(64)任务 ID(流程级变量为 NULL)
NAME_varchar(255)变量名(表单字段 field name)
VAR_TYPE_varchar(100)类型(string/long/integer/double/boolean/serializable)
TEXT_varchar(4000)字符串值
LONG_bigint长整型值
DOUBLE_double浮点型值
CREATE_TIME_datetime(3)创建时间

1.5 系统变量 vs 表单字段

查询时需要排除系统变量

系统变量名说明
PROCESS_STATUS流程状态
PROCESS_REASON审批原因
PROCESS_START_USER_ID发起人 ID
_FLOWABLE_SKIP_EXPRESSION_ENABLED跳过表达式标记
billCode单据编号
deptId / deptName部门信息
nrOfInstances / nrOfActiveInstances多实例计数

表单字段的变量名是 form-create 自动生成的随机 ID(如 Fcltmdk15xf0ahc),需对照 bpm_form.fields 才能知道中文标题。

2. 常用 SQL 查询模板

2.1 按流程实例 ID 查询所有变量

sql
SELECT 
    v.PROC_INST_ID_ AS 流程实例ID,
    v.NAME_ AS 变量名,
    v.VAR_TYPE_ AS 变量类型,
    v.TEXT_ AS 值,
    v.CREATE_TIME_ AS 创建时间
FROM ACT_HI_VARINST v
WHERE v.PROC_INST_ID_ = '指定流程实例ID'
  AND v.TASK_ID_ IS NULL  -- 只看流程级变量
ORDER BY v.CREATE_TIME_;

2.2 按单据编号查询

sql
SELECT 
    p.ID_ AS 流程实例ID,
    p.PROC_DEF_KEY_ AS 流程Key,
    p.START_TIME_ AS 发起时间,
    v.NAME_ AS 变量名,
    v.TEXT_ AS
FROM ACT_HI_PROCINST p
JOIN ACT_HI_VARINST bill ON p.ID_ = bill.PROC_INST_ID_ 
    AND bill.NAME_ = 'billCode'
JOIN ACT_HI_VARINST v ON p.ID_ = v.PROC_INST_ID_ 
    AND v.TASK_ID_ IS NULL
WHERE bill.TEXT_ = '指定单据编号'
ORDER BY v.NAME_;

2.3 按流程 Key 批量查询(行转列)

sql
SELECT 
    p.ID_ AS 流程实例ID,
    p.START_TIME_ AS 发起时间,
    MAX(CASE WHEN v.NAME_ = 'billCode' THEN v.TEXT_ END) AS 单据编号,
    MAX(CASE WHEN v.NAME_ = 'PROCESS_STATUS' THEN v.TEXT_ END) AS 流程状态,
    MAX(CASE WHEN v.NAME_ = '字段1' THEN v.TEXT_ END) AS 字段1标题,
    MAX(CASE WHEN v.NAME_ = '字段2' THEN v.TEXT_ END) AS 字段2标题
FROM ACT_HI_PROCINST p
JOIN ACT_HI_VARINST v ON p.ID_ = v.PROC_INST_ID_ 
    AND v.TASK_ID_ IS NULL
WHERE p.PROC_DEF_KEY_ = '指定流程Key'
GROUP BY p.ID_, p.START_TIME_
ORDER BY p.START_TIME_ DESC;

2.4 查询表单字段定义

sql
SELECT 
    f.id AS 表单ID,
    f.name AS 表单名称,
    JSON_EXTRACT(f.fields, '$[*].field') AS 字段名列表,
    JSON_EXTRACT(f.fields, '$[*].title') AS 字段标题列表
FROM bpm_form f
WHERE f.name LIKE '%关键词%';

3. 万能 SQL 生成器

输入流程 Key,自动生成完整的行转列查询:

sql
-- 步骤 1:先查出表单定义的字段列表
SELECT f.id, f.name, f.fields
FROM bpm_form f
JOIN bpm_process_definition_info pdi ON pdi.form_id = f.id
JOIN ACT_RE_PROCDEF pd ON pd.ID_ = pdi.process_definition_id
WHERE pd.KEY_ = '你的流程Key'
ORDER BY pd.VERSION_ DESC
LIMIT 1;

-- 步骤 2:根据 fields JSON 中的字段,手动生成 MAX(CASE WHEN ...) 语句
-- 每个 fields 数组元素的 "field" 是变量名,"title" 是中文标题

4. JSON 字段解析

bpm_form.fields 存储的是双层 JSON(JSON 字符串内嵌 JSON),使用 MySQL 的 JSON_EXTRACT 函数解析:

sql
-- 解析表单字段定义
SELECT 
    JSON_EXTRACT(fields, '$[0].field') AS 第一个字段名,
    JSON_EXTRACT(fields, '$[0].title') AS 第一个字段标题,
    JSON_LENGTH(fields) AS 字段总数
FROM bpm_form
WHERE id = 指定ID;

5. 注意事项

  1. 流程级变量:查询时过滤 TASK_ID_ IS NULL,只看流程级变量
  2. 值类型:所有类型都会有 TEXT_ 文本表示,数值类型额外有 LONG_DOUBLE_
  3. JSON 值:某些字段值本身是 JSON 字符串(如数组、对象),需要用 JSON 函数进一步解析
  4. 性能:大量数据查询时建议加索引 PROC_INST_ID_ + NAME_
  5. 历史 vs 运行时:优先查 ACT_HI_VARINST(包含所有数据),ACT_RU_VARIABLE 仅包含运行中的流程
  6. 业务表单不适用:本指南仅适用于流程表单(NORMAL),业务表单(CUSTOM)直接查对应业务表即可