复杂sql查询关键字“JSON_TABLE"无法解析

138 阅读3分钟

问题描述:

对象:数据库中一个字段addressJson,存储地址对象数组的JSON串;
对象示例
[{"addressType":"1","inputType":"1","provinceCode":"140000","province":"山西省","selectOption":["140000","140100","140101"],"selectOptionStr":"山西省/太原市/市辖区","addressDetails":"","mapAddress":"","coordinate":"","overseaAddress":""},{"addressType":"1","inputType":"1","provinceCode":"130000","province":"河北省","selectOption":["130000","130200","130203"],"selectOptionStr":"河北省/唐山市/路北区","addressDetails":"","mapAddress":"","coordinate":"","overseaAddress":""}]
需求:这个字段中可能有多个地址对象,需要将多个地址对象拆解出来,并将这多个对象中的province字段单独提取出来;

解决方案:

实现思路:博主使用的是Oracle数据库,支持使用关键字JSON_TABLE来解析存储JSON数据类型的字段,可以使用这个关键字来提取字段中所有的地址对象,从而取出对象中的province字段;
具体实现

SELECT *  
FROM  
TABLE_A t,  
JSON_TABLE(  
    t.PROJECT_ADDRESS_JSON, -- JSON 字段  
    '$[*]' -- 表示 JSON 数组中的所有对象  
    COLUMNS (  
    ADDRESS_TYPE VARCHAR2(10) PATH '$.addressType', -- 提取 addressType  
    PROVINCE VARCHAR2(50) PATH '$.province' -- 提取 province  
)  
) jt  
WHERER jt.ADDRESS_TYPE = 1 and jt.PROVINCE is not NULL;

新的问题:

上述代码写入mapper.xml文件后,访问时一直报错,错误信息如下:

Caused by: net.sf.jsqlparser.parser.ParseException: Encountered unexpected token: "(" "("

后查询网上博客后查询到了解决方案,需要在mapper接口文件的方法上加上注解@InterceptorIgnore(tenantLine = "1")即可解决,具体原理询问deepseek,回答如下,真实性见仁见智:

为什么添加 @InterceptorIgnore 能解决问题?

1. 多租户插件的干扰

  • MyBatis-Plus 或其他框架的 租户拦截器 会自动在 SQL 中插入租户条件(如 AND tenant_id = xxx)。
  • 当你的 SQL 中包含复杂语法(如 JSON_TABLE)时,拦截器可能会错误地修改 SQL 结构,导致语法解析失败(如误在 JSON_TABLE 内部插入条件,破坏 JSON 路径表达式)。

2.  @InterceptorIgnore 的作用

  • @InterceptorIgnore(tenantLine = "1") 的作用是 禁用当前 SQL 的租户拦截器,避免框架自动添加租户条件。
  • 禁用后,SQL 会按原样执行,不再被拦截器修改,因此 JSON_TABLE 语法能正确解析。

关键点分析

场景行为结果
未加注解租户拦截器尝试修改 SQL,可能在 JSON_TABLE 内部插入条件破坏 JSON 语法,导致 ParseException
添加注解拦截器被禁用,SQL 保持原样语法正确,执行成功

更深入的解决方案

如果不想全局禁用租户拦截器,可以进一步优化:

1. 检查租户拦截器的实现

  • 确认拦截器是否支持忽略特定 SQL 片段(如通过注释标记)。
  • 例如,MyBatis-Plus 的租户拦截器默认会忽略包含 @SqlParser(filter=true) 的方法。

2. 调整 SQL 写法

  • 将 JSON_TABLE 部分提取到子查询或嵌套查询中,减少拦截器误判的可能性。

3. 升级框架版本

  • 某些旧版拦截器对复杂 SQL 支持较差,升级 MyBatis-Plus 或其他相关库可能解决问题。

总结

  • 根本原因:多租户拦截器错误地修改了包含 JSON_TABLE 的 SQL,导致语法解析失败。

  • 解决方案

    • 使用 @InterceptorIgnore(tenantLine = "1") 临时禁用拦截器(推荐)。
    • 长期方案:优化拦截器逻辑或升级框架版本。

这种方法既能保留多租户功能,又能兼容复杂 SQL 语法。