You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

前端用sql-formatter解析含嵌套concat的MyBatis SQL失败求助

解决sql-formatter解析嵌套concat/含trim的concat SQL失败问题

问题根源

sql-formatter默认的语法解析器对嵌套函数(比如concat套concat、concat里嵌trim)的递归处理逻辑有缺陷,再加上MyBatis的#{var}语法需要额外兼容,直接导致解析时抛出Parse error。之前用简单自定义正则只能覆盖单层函数,搞不定嵌套场景。

可行解决办法

1. 扩展sql-formatter的自定义语法规则

通过更精准的规则配置,让解析器支持嵌套函数识别:

import sqlFormatter from 'sql-formatter';

const customConfig = {
  // 兼容MyBatis的参数语法
  paramTypes: [{ regex: /#\{[^}]+\}/g, type: 'parameter' }],
  // 标记concat、trim为可嵌套的函数
  functions: [
    { name: 'concat', openParens: '(', closeParens: ')', nested: true },
    { name: 'trim', openParens: '(', closeParens: ')', nested: true }
  ],
  // 强化括号匹配逻辑,处理嵌套括号
  brackets: [
    { open: '(', close: ')', escape: false },
    { open: "'", close: "'", escape: true }
  ]
};

// 调用格式化
const formattedSql = sqlFormatter.format(yourCompressedSql, {
  ...customConfig,
  language: 'mysql' // 替换成你用的数据库方言
});

这个方案直接从解析规则层面解决问题,能覆盖大部分嵌套场景。

2. 预处理SQL再格式化

如果扩展规则还是搞不定,可以用“占位符替换”的迂回手段:

// 预处理:把嵌套的concat/trim换成唯一占位符
function preprocessSql(sql) {
  // 递归匹配嵌套的concat和trim
  const nestedFuncRegex = /(concat|trim)\(([^()]+|(?R))*\)/g;
  const placeholders = [];
  let processed = sql.replace(nestedFuncRegex, (match) => {
    const key = `__FUNC_${placeholders.length}__`;
    placeholders.push({ key, value: match });
    return key;
  });
  return { processed, placeholders };
}

// 格式化后还原占位符
const { processed, placeholders } = preprocessSql(yourCompressedSql);
let formatted = sqlFormatter.format(processed, {
  paramTypes: [{ regex: /#\{[^}]+\}/g, type: 'parameter' }],
  language: 'mysql'
});
placeholders.forEach(item => {
  formatted = formatted.replace(new RegExp(item.key, 'g'), item.value);
});

这个方法通过把复杂嵌套函数临时“藏起来”,避免解析器出错,格式化完成后再还原,兼容性拉满。

3. 换用更兼容的格式化库

如果sql-formatter的扩展能力实在不够,试试pg-formatter或sqlfmt,这些库对嵌套函数的支持更好,同时配置MyBatis参数兼容:

import pgFormatter from 'pg-formatter';

const formattedSql = pgFormatter.format(yourCompressedSql, {
  indent: 2,
  // 让识别器兼容MyBatis的参数语法
  extraKeywords: ['#{', '}']
});

验证示例

针对报错的测试SQL:

SELECT * FROM user WHERE name = concat('a', concat('b', trim('  c  '))) AND id = #{userId}

用上述方案处理后,能正常输出格式化结果:

SELECT
  *
FROM
  user
WHERE
  name = concat('a', concat('b', trim('  c  ')))
  AND id = #{userId}

内容的提问来源于stack exchange,提问作者We He

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 02:58:23