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

求助:使用ANTLR4解析MySQL查询并提取组件的简单示例

我完全懂你现在的困惑——用Maven把ANTLR4的MySQL语法生成了Java类,但对着一堆自动生成的代码,完全不知道怎么下手解析SQL、提取那些像选中列、表名、WHERE条件这些关键组件对吧?别担心,我给你一个简单又完整的示例,一步步带你搞定核心逻辑。

核心思路:用ANTLR Visitor遍历语法树

ANTLR生成的Parser会把SQL转换成一棵语法树,我们要做的就是遍历这棵树,在对应的节点上提取我们需要的信息。最灵活的方式是用Visitor模式——继承ANTLR自动生成的MySQLBaseVisitor,重写对应语法规则的访问方法,在方法里收集数据。

第一步:自定义Visitor类(收集我们需要的信息)

这个类负责遍历语法树,把选中列、表名、WHERE条件这些信息存起来:

import org.antlr.v4.runtime.tree.ParseTree;
import java.util.ArrayList;
import java.util.List;

public class MySQLQueryExtractor extends MySQLBaseVisitor<Void> {
    // 存储提取到的选中列
    private final List<String> selectedColumns = new ArrayList<>();
    // 存储表名
    private final List<String> tableNames = new ArrayList<>();
    // 存储WHERE条件内容
    private String whereCondition;

    // 访问SELECT语句的顶层节点
    @Override
    public Void visitSelectStatement(MySQLParser.SelectStatementContext ctx) {
        // 调用父类方法,自动遍历所有子节点
        return super.visitSelectStatement(ctx);
    }

    // 访问每个SELECT列项(比如id、name、email)
    @Override
    public Void visitSelectItem(MySQLParser.SelectItemContext ctx) {
        String columnText = ctx.getText();
        selectedColumns.add(columnText);
        return super.visitSelectItem(ctx);
    }

    // 访问表名节点
    @Override
    public Void visitTableName(MySQLParser.TableNameContext ctx) {
        String tableText = ctx.getText();
        tableNames.add(tableText);
        return super.visitTableName(ctx);
    }

    // 访问WHERE子句节点
    @Override
    public Void visitWhereClause(MySQLParser.WhereClauseContext ctx) {
        // 去掉"WHERE "前缀,只保留条件内容
        whereCondition = ctx.getText().substring(6).trim();
        return super.visitWhereClause(ctx);
    }

    // 对外提供获取提取结果的方法
    public List<String> getSelectedColumns() {
        return selectedColumns;
    }

    public List<String> getTableNames() {
        return tableNames;
    }

    public String getWhereCondition() {
        return whereCondition;
    }
}

第二步:编写主程序解析SQL

这部分负责初始化ANTLR的Lexer、Parser,生成语法树,然后用我们的自定义Visitor去遍历提取信息:

import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;

public class SQLParserDemo {
    public static void main(String[] args) {
        // 测试用的SQL语句
        String testSql = "SELECT id, name, email FROM users WHERE age > 18 AND status = 'active'";

        // 1. 把SQL转换成ANTLR能处理的字符流
        CharStream charStream = CharStreams.fromString(testSql);
        // 2. 用Lexer把字符流转换成Token(比如关键字、标识符、运算符这些)
        MySQLLexer lexer = new MySQLLexer(charStream);
        // 3. 用TokenStream管理Token序列
        CommonTokenStream tokenStream = new CommonTokenStream(lexer);
        // 4. 用Parser把Token序列生成语法树
        MySQLParser parser = new MySQLParser(tokenStream);
        // 5. 获取语法树的根节点(这里对应SELECT语句的顶层规则)
        ParseTree parseTree = parser.selectStatement();

        // 6. 用自定义Visitor遍历语法树,提取信息
        MySQLQueryExtractor extractor = new MySQLQueryExtractor();
        extractor.visit(parseTree);

        // 输出提取结果
        System.out.println("提取的选中列: " + extractor.getSelectedColumns());
        System.out.println("提取的表名: " + extractor.getTableNames());
        System.out.println("提取的WHERE条件: " + extractor.getWhereCondition());
    }
}

一些关键说明和扩展提示

  • 怎么找要重写的方法? 看自动生成的MySQLParser类,里面所有以Context结尾的内部类,对应语法文件里的规则。比如SubqueryContext对应子查询规则,如果你要提取子查询,就重写visitSubquery方法。
  • 处理更复杂的SQL:比如带别名的表(user u)、JOIN、函数调用(COUNT(id)),你需要重写对应的规则方法,比如TableReferenceContext来处理带别名的表,FunctionCallContext来处理函数列。
  • 调试小技巧:可以用ANTLR的可视化工具(antlr4-gui)把语法树画出来,直观看到每个节点对应的规则,这样就知道该重写哪个方法了。
  • 确保生成的类在classpath里:Maven生成的ANTLR类默认在target/generated-sources/antlr4目录,要让IDE把这个目录标记为源目录,不然会找不到MySQLLexer、MySQLParser这些类。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 02:23:38