如何用Regex或JavaScript正确提取SQL查询中的关键信息?
提取SQL查询关键信息的可靠方案
问题背景
我们需要从SQL查询字符串中提取表名、筛选条件、Limit等关键信息,例如:
给定SQL语句:
const sql = "select * from products where id=1 and description like '%thick and crispy%'";
期望提取的筛选条件为:
const filters = ["id=1","description like '%thick and crispy%'"];
最初尝试用简单的正则拆分:
const filters = sql.split(/ and /gi);
但这种方式存在明显缺陷:当筛选条件的值本身包含and(比如示例里的%thick and crispy%)时,会错误拆分条件;同时还需要处理不区分大小写的SQL关键字、LIKE/OR/IN等多种子句,简单拆分完全无法满足需求。
解决方案
方案1:优化后的正则表达式
通过精准的正则匹配,避开字符串内部的关键字,正确拆分筛选条件。核心思路是先定位WHERE子句范围,再区分引号/括号内的内容和外部的逻辑运算符。
示例代码:
function extractFilters(sql) { // 提取WHERE到下一个关键字(或结尾)的内容 const whereMatch = sql.match(/where\s+(.*?)(?=\s+(limit|order by|group by|$))/i); if (!whereMatch) return []; const whereClause = whereMatch[1]; // 拆分条件,忽略引号、括号内的AND/OR const filterRegex = /([^'"()]+(?:\(['"](?:[^'"\\]|\\.)*['"]\))?)(?=\s+(and|or)\s+|$)/gi; const filters = []; let match; while ((match = filterRegex.exec(whereClause)) !== null) { filters.push(match[1].trim()); } return filters; } // 测试复杂场景 const testSql = "select * from products where id=1 and description like '%thick and crispy%' or category in ('electronics', 'home and garden')"; console.log(extractFilters(testSql)); // 输出: ["id=1", "description like '%thick and crispy%'", "category in ('electronics', 'home and garden')"]
注意:正则仅适用于结构不复杂的SQL,遇到嵌套子查询、多层嵌套括号等场景时,依然可能出现解析错误。
方案2:使用专门的SQL解析库(推荐)
通过JavaScript的SQL解析库,将SQL转换为抽象语法树(AST),再从AST中提取所需信息,这是最可靠的方案,能处理几乎所有合法SQL语法。
以sql-parser-mysql为例(可通过npm直接安装),示例代码:
const parser = require('sql-parser-mysql'); function parseSQL(sql) { try { const ast = parser.parse(sql); const result = { tableName: ast.from[0].table, filters: [], limit: ast.limit ? ast.limit.value : null }; // 遍历WHERE条件节点,提取筛选规则 function traverseCondition(node) { if (node.type === 'binary_expr') { if (['AND', 'OR'].includes(node.operator.toUpperCase())) { // 递归处理AND/OR连接的子条件 traverseCondition(node.left); traverseCondition(node.right); } else { // 拼接单个条件表达式 const left = node.left.value; const operator = node.operator; let right = node.right.value; if (node.right.type === 'string') { right = `'${right}'`; } result.filters.push(`${left} ${operator} ${right}`); } } else if (node.type === 'function') { // 处理IN等函数式条件 const args = node.args.map(arg => arg.type === 'string' ? `'${arg.value}'` : arg.value ).join(', '); result.filters.push(`${node.name}(${args})`); } } if (ast.where) { traverseCondition(ast.where); } return result; } catch (err) { console.error('SQL解析失败:', err); return null; } } // 测试示例 const testSql = "select * from products where id=1 and description like '%thick and crispy%' limit 10"; const parsedResult = parseSQL(testSql); console.log(parsedResult); /* 输出: { tableName: 'products', filters: [ 'id = 1', 'description like \'%thick and crispy%\'' ], limit: 10 } */
总结
- 简单SQL场景:可以用优化后的正则快速实现需求
- 复杂SQL场景:优先使用专门的SQL解析库,保证稳定性和兼容性
内容的提问来源于stack exchange,提问作者Mitanshu
相关产品推荐
相关产品推荐

