如何使用SQL子查询实现多级审批流程的状态跟踪?

阿静小哥_5311

阿静小哥_5311

2026-06-07

762人浏览

原创

子查询不能驱动多级审批流程状态跟踪,因其仅作快照式查找,无法表达“流程进度”语义;正确做法是结合状态字段、审批记录表及分层逻辑,通过校验前序完成、本步启用与权限匹配来判定当前待办节点。

如何使用sql子查询实现多级审批流程的状态跟踪?

子查询本身不能驱动多级审批流程的状态跟踪,它只是状态查询的辅助工具;真正需要的是设计合理的状态字段、审批记录表和分层查询逻辑。

为什么直接用子查询查“当前审批人”容易出错

常见错误是写类似 SELECT (SELECT user_id FROM approvals WHERE step = (SELECT MAX(step) FROM approvals WHERE doc_id = t.id AND status = 'pending')) FROM docs t —— 这种嵌套在数据不完整(比如某步被跳过、状态未及时更新)时会返回空或错值。

根本问题在于:子查询无法表达“流程进度”的语义,它只做快照式查找。实际审批中,“当前待办”取决于上一步是否完成 + 本步是否启用 + 权限是否匹配,不是单纯取最大 step。

  • 审批步骤可能非连续(如 step=1,3,5),MAX(step) 会漏掉中间跳转逻辑
  • 同一 doc_id 可能存在多条 status = 'pending' 记录(并发提交冲突)
  • 子查询不校验时间顺序,created_at 滞后于前序完成时间的记录会被误判为“当前”

用关联子查询查“各环节处理结果”更可靠

把每级审批结果作为独立列查出,比试图算出“当前谁该审”更稳定。适合报表、看板等读多写少场景。

示例结构:approvals(doc_id, step, user_id, status, approved_at),假设最多 3 级:

SELECT
  d.id,
  d.title,
  (SELECT status FROM approvals a1 WHERE a1.doc_id = d.id AND a1.step = 1) AS step1_status,
  (SELECT user_id FROM approvals a1 WHERE a1.doc_id = d.id AND a1.step = 1) AS step1_user,
  (SELECT approved_at FROM approvals a1 WHERE a1.doc_id = d.id AND a1.step = 1) AS step1_time,
  (SELECT status FROM approvals a2 WHERE a2.doc_id = d.id AND a2.step = 2) AS step2_status,
  (SELECT status FROM approvals a3 WHERE a3.doc_id = d.id AND a3.step = 3) AS step3_status
FROM docs d;

这样每列含义清晰,前端可直接判断:step1_status = 'approved' AND step2_status = 'pending' 即表示卡在第二步。

文智Doc
文智Doc

文智Doc是一款AI办公效率工具,AI 文档生成工具,一键生成初稿智能排版。

下载
  • 避免用 IN 或 EXISTS 替代——它们只返回布尔值,丢失具体状态细节
  • 对每 step 使用独立子查询,比 LEFT JOIN 更易控制 NULL 行为(尤其当某 step 尚未触发时)
  • 注意加索引:approvals(doc_id, step) 是必须的,否则 N+1 查询性能崩盘

用相关子查询判断“是否完成全流程”

检查所有必经步骤是否都为 'approved',比查“最后一步状态”更准确——因为流程可能支持条件分支,最后 step 不一定代表终态。

关键逻辑:只有当指定步骤全部存在且状态达标,才算完成。

SELECT id, title,
  CASE
    WHEN (
      SELECT COUNT(*) = 3 FROM (
        SELECT 1 FROM approvals a WHERE a.doc_id = d.id AND a.step IN (1,2,3) AND a.status = 'approved'
      ) t
    ) THEN 'completed'
    ELSE 'in_progress'
  END AS flow_status
FROM docs d;

这个写法强制要求 step 1/2/3 全部存在且通过,不会被“step=3 已批但 step=1 被撤回”这类异常绕过。

  • 若步骤数动态配置,需改用 SELECT COUNT(DISTINCT step) 配合步骤定义表
  • 别用 NOT EXISTS (SELECT ... WHERE status != 'approved')——它会把缺失记录也判为 TRUE
  • MySQL 8.0+ 可考虑用 JSON_CONTAINS 预存步骤规则,但子查询方式兼容性更好

真正难的不是怎么写子查询,而是定义清楚“什么是审批完成”。流程引擎里常见的“并行分支”“驳回重走”“超时自动跳过”,这些状态转换规则必须先沉淀到业务逻辑或状态机表中,子查询只是把结果翻出来给你看。没想明白状态流转,再漂亮的 SQL 也是空中楼阁。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4623

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

951

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1209

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

6601

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3343

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

6580

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

9041

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1230

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1072

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 134.1万人学习