用java实现一个简单的sql select 解析器,无需第三方依赖,完全从0开始

以下是一个简单的 SQL SELECT 解析器的 Java 实现,支持单表查询和基本条件过滤。代码包含词法分析和语法分析模块,并支持以下语法:

SELECT column1, column2 FROM table WHERE column3 = 5


完整代码

1. Token 类型定义 (TokenType.java)

public enum TokenType {
SELECT, FROM, WHERE,
IDENTIFIER, COMMA, STAR, EQUALS,
STRING, NUMBER, EOF
}

2. Token 类 (Token.java)

public class Token {
public final TokenType type;
public final String value;

public Token(TokenType type, String value) {this.type = type;this.value = value;
}@Override
public String toString() {return String.format("(%s, %s)", type, value);
}

}

3. 词法分析器 (Lexer.java)

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Lexer {
private final String input;
private int pos = 0;

private static final Pattern TOKEN_PATTERN = Pattern.compile("(?i)(SELECT|FROM|WHERE)" +    // 关键字 (不区分大小写)"|([a-zA-Z_][a-zA-Z0-9_]*)" + // 标识符"|(\\*)" +                    // 星号"|(,)" +                      // 逗号"|(=)" +                      // 等于号"|('([^']*)')" +              // 字符串字面量"|(\\d+)" +                   // 数字"|(\\s+)"                     // 空白字符 (跳过)
);public Lexer(String input) {this.input = input;
}public ArrayList<Token> tokenize() {ArrayList<Token> tokens = new ArrayList<>();Matcher matcher = TOKEN_PATTERN.matcher(input);while (pos < input.length()) {if (!matcher.find(pos)) {throw new RuntimeException("Invalid token at position: " + pos);}// 跳过空白字符if (matcher.group(7) != null) {pos = matcher.end();continue;}// 匹配其他 Tokenfor (int i = 1; i <= matcher.groupCount(); i++) {if (matcher.group(i) != null) {TokenType type = null;String value = matcher.group(i);switch (i) {case 1:  // 关键字type = TokenType.valueOf(value.toUpperCase());break;case 2:  // 标识符type = TokenType.IDENTIFIER;break;case 3:  // *type = TokenType.STAR;break;case 4:  // ,type = TokenType.COMMA;break;case 5:  // =type = TokenType.EQUALS;break;case 6:  // 字符串 (带引号)type = TokenType.STRING;value = matcher.group(7);  // 去掉引号break;case 8:  // 数字type = TokenType.NUMBER;break;}if(type!=null){tokens.add(new Token(type, value));}pos = matcher.end();break;}}}tokens.add(new Token(TokenType.EOF, ""));return tokens;
}

}

4. AST 结构类 (SelectQuery.java)

import java.util.List;

public class SelectQuery {
public List columns;
public String table;
public Condition whereCondition;

public static class Condition {public String column;public String operator;public String value;
}

}

5. 语法解析器 (Parser.java)

import java.util.ArrayList;
import java.util.List;

public class Parser {
private final List tokens;
private int pos = 0;

public Parser(List<Token> tokens) {this.tokens = tokens;
}public SelectQuery parse() {SelectQuery query = new SelectQuery();parseSelect(query);parseFrom(query);parseWhere(query);return query;
}private void parseSelect(SelectQuery query) {consume(TokenType.SELECT);query.columns = new ArrayList<>();if (peek().type == TokenType.STAR) {consume(TokenType.STAR);query.columns.add("*");} else {do {query.columns.add(consume(TokenType.IDENTIFIER).value);} while (match(TokenType.COMMA));}
}private void parseFrom(SelectQuery query) {consume(TokenType.FROM);query.table = consume(TokenType.IDENTIFIER).value;
}private void parseWhere(SelectQuery query) {if (match(TokenType.WHERE)) {SelectQuery.Condition condition = new SelectQuery.Condition();condition.column = consume(TokenType.IDENTIFIER).value;consume(TokenType.EQUALS);Token valueToken = peek();if (valueToken.type == TokenType.STRING || valueToken.type == TokenType.NUMBER) {condition.value = valueToken.value;advance();} else {throw new RuntimeException("Expected string or number");}query.whereCondition = condition;}
}private Token consume(TokenType expected) {Token token = peek();if (token.type != expected) {throw new RuntimeException("Expected " + expected + ", found " + token.type);}advance();return token;
}private boolean match(TokenType type) {if (peek().type == type) {advance();return true;}return false;
}private Token peek() {return tokens.get(pos);
}private void advance() {pos++;
}

}

6. 测试主类 (Main.java)

import java.util.List;

public class Main {
public static void main(String[] args) {
String sql = “SELECT id, name FROM users WHERE age = 25”;
Lexer lexer = new Lexer(sql);
List tokens = lexer.tokenize();
Parser parser = new Parser(tokens);
SelectQuery query = parser.parse();

    System.out.println("Columns: " + query.columns);System.out.println("Table: " + query.table);if (query.whereCondition != null) {System.out.println("WHERE " + query.whereCondition.column + " = " + query.whereCondition.value);}
}

}


代码说明

  1. 词法分析器 (Lexer)

    • 使用正则表达式匹配 SQL 关键字、标识符、数字、字符串等 Token。
    • 跳过空白字符,返回 Token 列表。
  2. 语法解析器 (Parser)

    • 递归下降解析器,依次解析 SELECTFROMWHERE 子句。
    • 构建 SelectQuery 对象存储解析结果。
  3. AST 结构 (SelectQuery)

    • 保存查询的列、表名和过滤条件。
  4. 测试示例 (Main)

    • 输入 SQL 语句,输出解析后的结构。

运行结果

Columns: [id, name]
Table: users
WHERE age = 25


支持特性

  • 单表 SELECT 查询
  • 列名列表或 *
  • 简单的 WHERE 条件(仅支持 = 和字符串/数字值)

可根据需要扩展 WHERE 条件(如 >, <, AND/OR)和更复杂的数据类型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/81667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里云 CentOS YUM 源配置指南

阿里云 CentOS YUM 源配置指南 在使用 CentOS 7 时&#xff0c;由于 CentOS 官方源停止维护等原因&#xff0c;yum install 命令可能会报错 “Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64”。以下是通过更换阿里云源解决该问题的详细步骤。 一、备份原有配…

Learning vtkjs之ThresholdPoints

过滤器 阈值过滤器 介绍 vtkThresholdPoints - 提取满足阈值条件的点 vtkThresholdPoints 是一个过滤器&#xff0c;它从数据集中提取满足阈值条件的点。该条件可以采用三种形式&#xff1a; 1&#xff09;大于特定值&#xff1b; 2) 小于特定值&#xff1b; 3) 在特定值之间…

记录ruoyi-flowable-plus第一次运行流程报错

记录ruoyi-flowable-plus第一次运行流程报错 错误步骤 1.启动ruoyi-flowable-plus 正常登录后&#xff0c;打开流程分类然后点击新增按钮&#xff0c;新增了一个分类。增加成功后&#xff0c; 再点击流程分类&#xff0c;报错。 错误提示 org.springframework.cglib.core.C…

Java中的stream流介绍与使用

一、Stream 的基础概念 定义与特性 Stream 是单向数据流&#xff0c;对集合或数组进行高效处理&#xff0c;不存储数据&#xff0c;而是通过操作链生成新 Stream。不可变性&#xff1a;原始数据源不被修改&#xff0c;所有操作均返回新 Stream。延迟执行&#xff1a;中间操作&a…

OCR身份证识别(正反面)_个人证照OCR识别_开放API接口使用指南

一、接口简介 在数字化时代&#xff0c;快速准确地提取身份证信息变得尤为重要。**万维易源提供的“身份证OCR识别”API接口&#xff0c;能够快速提取二代居民身份证正反面的所有字段信息&#xff0c;包括姓名、性别、民族、出生日期、住址、身份证号、签发机关、有效期限等。…

25年新版潮乎盲盒系统源码 盲盒商城系统前端分享

盲盒系统市场的前景一直都很不错&#xff0c;最近很多问我有没有盲盒源码的客户&#xff0c;下面给大家分享一个新版潮乎盲盒源码&#xff01; 这款盲盒源码系统 前端Uniapp 后端使用了Laravel框架进行开发。Laravel是一个流行的PHP框架&#xff0c;具有强大的功能和易于使用的…

Transformer四模型回归打包(内含NRBO-Transformer-GRU、Transformer-GRU、Transformer、GRU模型)

Transformer四模型回归打包&#xff08;内含NRBO-Transformer-GRU、Transformer-GRU、Transformer、GRU模型&#xff09; 目录 Transformer四模型回归打包&#xff08;内含NRBO-Transformer-GRU、Transformer-GRU、Transformer、GRU模型&#xff09;预测效果基本介绍程序设计参…

Axure疑难杂症:利用中继器制作三级下拉菜单(逻辑判断进阶)

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 课程主题:三级下拉菜单 主要内容:条件筛选时的逻辑判断思维,中继器使用 应用场景:复合条件下的下拉列表制作 案例展…

Nginx 核心功能之正反代理

目录 一、Nginx 二、正向代理 三、反向代理 四、Nginx 缓存 1. 缓存功能的核心原理和缓存类型 2. 代理缓存功能设置 五、Nginx rewrite和正则 &#xff08;1&#xff09;Nginx 正则 &#xff08;2&#xff09;nginx location &#xff08;3&#xff09;Rewrite &…

ssh连接云服务器记录

文章目录 1. 背景2. ssh连接2.1 win 下通过终端工具进行连接2.2 Linux下通过ssh指令连接2.3 ssh使用publickey来连接 ssh连接云服务器记录 1. 背景 最近开始接触docker技术、mysql技术&#xff0c;加上本人工作基本都在Linux下进行&#xff0c;因此需要一套Linux环境进行练习。…

软考-软件设计师中级备考 12、软件工程

一、软件工程概述 定义&#xff1a;软件工程是一门研究用工程化方法构建和维护有效的、实用的和高质量软件的学科。它涉及到软件的开发、测试、维护、管理等多个方面&#xff0c;旨在运用一系列科学方法和技术手段&#xff0c;提高软件的质量和开发效率&#xff0c;降低软件开…

【多次弹出“获取打开此tobiieyetracking链接的应用”的窗口】解决办法

使用联想R9000P突然出现“获取打开此tobiieyetracking链接的应用”的窗口&#xff0c;每隔几分钟就弹一次&#xff0c;特别恶心人&#xff0c;解决办法&#xff1a; 找到【此电脑】&#xff0c;鼠标右键【管理】&#xff1b;选择【服务】&#xff0c;如下所示&#xff0c;找到…

项目选择的三个核心因素:市场前景、竞争优势和成本控制

能保持持续增长和赚钱的项目就是好项目。 每个创业者创业之初&#xff0c;遇到的第一个难题就是选择做什么项目&#xff1f; 俗话说&#xff1a;方向不对&#xff0c;努力白费。 选错项目&#xff0c;意味着你所有的付出都是打水漂。 能做的项目那么多&#xff0c;在没有价值…

裸机 Kubernetes 集群负载均衡器:MetalLB 深度解析与实战指南

一、引言 在云原生架构中&#xff0c;Kubernetes 默认的负载均衡能力依赖于云厂商&#xff08;如 AWS ELB、GCP LB&#xff09;&#xff0c;但在裸机或本地数据中心环境中&#xff0c;这一功能缺失导致 LoadBalancer 类型的 Service 始终处于 Pending 状态。此时&#xff0c;M…

2025年- H20-Lc128-240. 搜索二维矩阵 II(矩阵)---java版

1.题目描述 2.思路 遍历矩阵&#xff0c;然后如果遇到矩阵中的值正好等于target&#xff0c;输出true。否则&#xff0c;输出false。 3.代码 public class H240 {public boolean searchMatrix(int[][] matrix, int target) {//1.计算出总的行值&#xff0c;总的列值。int mm…

系统架构设计师:设计模式——行为设计模式

一、行为设计模式 行为模式涉及算法和对象间职责的分配。行为模式不仅描述对象或类的模式&#xff0c;还描述它们之间的通信模式。这些模式刻画了在运行时难以跟踪的、复杂的控制流。它们将用户的注意力从控制流转移到对象间的联系方式上来。 行为类模式使用继承机制在类间分…

java springboot实现MCP Server SSE

参考&#xff1a; https://juejin.cn/post/7491881721278529570 SpringAI 实现 SSE MCP Server项目 - Auler - 博客园 springboot-MCPserver-JUnit: 使用springboot支持mcp项目搭建&#xff0c;同时有着便捷的单元测试来进行敏捷开发对话即服务&#xff1a;Spring BootMCP让…

LeetCode 热题 100 48. 旋转图像

LeetCode 热题 100 | 48. 旋转图像 大家好&#xff0c;今天我们来解决一道经典的算法题——旋转图像。这道题在LeetCode上被标记为中等难度&#xff0c;要求我们将一个 n n 的二维矩阵&#xff08;图像&#xff09;顺时针旋转90度&#xff0c;并且必须原地修改矩阵&#xff0…

嵌入式按键原理、中断过程与中断程序设计(键盘扫描程序)

按键去抖动  通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时&#xff0c;电压信号波型如下图。由于机械触点的弹性作用&#xff0c;一个按键开关在闭合时不会马上稳定地接通&#xff0c;在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。…

数据结构之哈夫曼树

8.哈夫曼树 8.1 哈夫曼编码 哈夫曼编码&#xff08;Huffman Coding&#xff09;&#xff0c;又称霍夫曼编码&#xff0c;是一种可变字长编码&#xff08;VLC&#xff09;方式 这种编码方法完全依据字符出现的概率来构造异字头的平均长度最短的码字&#xff0c; 因此有时也被…