用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.pswp.cn/diannao/81667.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/81667.shtml
英文地址,請注明出處:http://en.pswp.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; 因此有時也被…