最近在处理计资名单账期中间表数据时,遇到一个比较隐蔽的问题:SQL 在 PostgreSQL 客户端中可以正常执行,但放到 MyBatis XML 里执行却失效或报错。

问题 SQL 大致如下:
<delete id="deleteLockedLeaveJobs" parameterType="java.util.Map">
DELETE FROM xxx.salary_list_middle_monthly t1
USING xxx.salary_list t2
WHERE t1.task_unique_id = #{taskUniqueId}
AND t2.ytenant_id = #{ytenantId}
AND t1.staff_id = t2.staff_id
AND t1.period = t2.period
AND t2.dr = 0
AND t1.depart_date IS NOT NULL
AND t1.depart_date <![CDATA[ < ]]> #{today}
</delete>
这段 SQL 的业务含义是:
这段 SQL 直接放到 PostgreSQL 数据库工具里执行是正常的。
但是放到项目 MyBatis XML 中,通过程序执行时,可能出现:
SQL 执行失败
SQL 被框架改写
SQL 结构被重新排序
DELETE USING 语法失效
一开始容易误以为是 PostgreSQL SQL 写法有问题。
但实际排查后发现,问题不在数据库本身,而更可能出在项目里的 SQL 解析、租户翻译、数据权限、SQL 改写等框架层。
PostgreSQL 支持这种写法:
DELETE FROM table1 t1
USING table2 t2
WHERE t1.id = t2.id;
这是 PostgreSQL 中常用的关联删除语法。
但是在某些项目框架里,MyBatis 执行 SQL 前,SQL 可能会经过一层或多层处理,例如:
租户字段注入
SQL 翻译
数据权限拦截
SQL 解析器重写
多数据源适配
这些组件有时对 PostgreSQL 的 DELETE ... USING ... 语法支持不完整。
尤其是遇到下面这种结构时:
DELETE FROM schema.table t1
USING schema.table2 t2
WHERE ...
框架可能会错误识别:
表别名
USING 语法
DELETE 目标表
关联表
WHERE 条件归属
最后导致原本正确的 PostgreSQL SQL,在进入数据库前已经被框架改坏了。
所以这个问题的关键不是:
PostgreSQL 不支持 DELETE USING
而是:
项目框架中的 SQL 翻译/拦截逻辑没有正确处理 PostgreSQL 的 DELETE USING 语法
最终处理方式是在 SQL 前加上跳过翻译的标记,并把别名写得更明确:
<delete id="deleteLockedLeaveJobs" parameterType="java.util.Map">
/*!sql_no_translate*/
DELETE FROM xxx.salary_list_middle_monthly t1
USING xxx.salary_list AS t2
WHERE t1.task_unique_id = #{taskUniqueId}
AND t2.ytenant_id = #{ytenantId}
AND t1.staff_id = t2.staff_id
AND t1.period = t2.period
AND t2.dr = 0
AND t1.depart_date IS NOT NULL
AND t1.depart_date <![CDATA[ < ]]> #{today}
</delete>
关键改动有两个:
1. 增加 /*!sql_no_translate*/
2. USING 表别名改成显式 AS t2
其中最核心的是:
/*!sql_no_translate*/
它的作用是告诉项目框架:
AS t2 不是必须解决点,但可以让 SQL 语义更清晰,减少部分 SQL 解析器对别名的误判。
这个问题很典型。
数据库客户端执行时,链路是:
SQL → PostgreSQL
而项目中执行时,链路可能是:
MyBatis XML
→ MyBatis 参数替换
→ 框架 SQL 拦截器
→ 租户/权限/翻译处理
→ JDBC
→ PostgreSQL
所以你在数据库里验证通过,只能说明:
SQL 本身符合 PostgreSQL 语法
但不能说明:
这段 SQL 在项目框架链路中不会被改写
如果项目里有 SQL 拦截器、租户插件、数据权限插件、SQL 翻译组件,就要特别注意这种差异。
遇到这类问题时,不要只盯着 SQL 本身,可以按下面顺序排查:
如果数据库中都不能执行,那就是 SQL 写法问题。
如果数据库中可以执行,但项目中失败,继续往下查。
重点看程序最终发给数据库的 SQL,是否和 XML 里写的一致。
如果发现 SQL 被改写、排序、加条件、换别名,就说明中间有框架处理。
常见影响点包括:
租户字段自动注入
数据权限 SQL 改写
分页插件
多数据库方言转换
SQL 翻译器
自定义 MyBatis Interceptor
例如:
/*!sql_no_translate*/
尤其是这类 PostgreSQL 语法:
DELETE ... USING ...
INSERT ... RETURNING ...
UPDATE ... FROM ...
DISTINCT ON (...)
LATERAL JOIN
IS DISTINCT FROM
这些语法在 PostgreSQL 中很常见,但某些通用 SQL 解析器未必支持完整。
这次问题的核心结论是:
对于 PostgreSQL 的特殊语法,尤其是:
DELETE ... USING ...
如果项目框架存在 SQL 改写能力,建议:
1. 优先打印最终 SQL;
2. 确认 SQL 是否被框架改写;
3. 必要时使用 sql_no_translate 跳过翻译;
4. 表别名尽量写完整,例如 USING table AS alias;
5. 不要只用数据库客户端执行结果判断项目一定没问题。
这类问题表面看是 SQL 报错,实际往往是框架链路问题。排查时要区分清楚:
数据库语法问题
和
项目框架 SQL 改写问题
否则很容易在 SQL 本身上反复修改,浪费大量时间。
明日之后账号出售平台推荐:安全靠谱的交易APP有哪些
今日2025小鸡最新答案7.7 支付宝小鸡最新答案2026年7月7日
晋江app怎么复制作品信息
三国杀钟会觉醒玩法详解 三国杀钟会角色技能解析与实战技巧
Microsoft-PowerPoint-Best-Practices-Tips-and-Techniques skill 配套代码先跑哪一段:看章节入口、依赖和输出文件(skill安装版)
愉客行怎么退票