Go語言從零構建SQL數據庫(6) - sql解析器(番外)- *號的處理

番外:處理SQL通配符查詢

在SQL中,SELECT * FROM table是最基礎的查詢之一,星號(*)是一個通配符,表示"選擇所有列"。雖然通配符查詢看起來簡單,但在解析器中需要特殊處理。下面詳細介紹我們如何實現這一常用功能。

1. 星號查詢的挑戰

星號與普通列名有本質區別:

  • 普通列名是標識符(如 idname
  • 星號是一個特殊符號,表示"全部"
  • 在解析時需要區別對待,不能簡單視為標識符
Token: *
特殊處理
SELECT * FROM users
詞法分析器
Token流
語法分析器
AST: AsteriskExpression

普通列名vs星號的處理差異

特性普通列名星號
語法標記標識符(IDENTIFIER)特殊字符(ASTERISK)
AST節點IdentifierAsteriskExpression
解析方法parseIdentifier()parseAsterisk()
語義驗證需要驗證列存在性不需要驗證(表示所有列)
執行時處理讀取單個列讀取所有列

2. 解析器中的實現

為了支持星號查詢,我們需要修改解析器的幾個關鍵部分:

步驟1:定義AST節點

首先,創建一個專用的AST節點類型表示星號:

// AsteriskExpression 表示SQL中的星號(*),用于表示選擇所有列
type AsteriskExpression struct{}func (a *AsteriskExpression) expressionNode() {}
func (a *AsteriskExpression) TokenLiteral() string { return "*" }
func (a *AsteriskExpression) String() string { return "*" }

這個簡單的結構體實現了 Expression接口,可以作為SELECT語句的列表達式。

?interface?
Expression
+expressionNode()
+TokenLiteral() : string
+String() : string
Identifier
+Value string
+expressionNode()
+TokenLiteral() : string
+String() : string
AsteriskExpression
+expressionNode()
+TokenLiteral() : string
+String() : string
LiteralExpression
+Value string
+Type TokenType
+expressionNode()
+TokenLiteral() : string
+String() : string

步驟2:注冊前綴解析函數

在解析器初始化時,為星號符號注冊專門的解析函數:

// 初始化解析器
func NewParser(l *lexer.Lexer) *Parser {p := &Parser{lexer:  l,errors: []string{},}// 注冊前綴解析函數p.prefixParseFns = make(map[lexer.TokenType]prefixParseFn)// ... 其他注冊p.registerPrefix(lexer.ASTERISK, p.parseAsterisk) // 添加對*的解析支持// ... 其他初始化return p
}

步驟3:實現星號解析函數

// parseAsterisk 解析SELECT語句中的星號(*),表示選擇所有列
func (p *Parser) parseAsterisk() (ast.Expression, error) {return &ast.AsteriskExpression{}, nil
}

這個函數非常簡單,只需創建并返回一個 AsteriskExpression實例。

星號解析的處理流程

SQL: SELECT * FROM users
詞法分析: [SELECT, *, FROM, users]
遇到 * Token
有注冊的parseAsterisk函數?
調用parseAsterisk()
解析錯誤
創建AsteriskExpression
將AsteriskExpression添加到SelectStatement的Columns列表
繼續解析FROM子句

3. 執行時的處理

當查詢執行器遇到 AsteriskExpression時,需要:

  1. 獲取表的元數據信息,找出所有列
  2. 按順序返回所有列的數據
  3. 保持列的原始順序
// 偽代碼:執行器如何處理星號
func executeSelect(stmt *ast.SelectStatement, db *Database) *ResultSet {// ...// 處理列選擇var columns []Columnfor _, colExpr := range stmt.Columns {switch expr := colExpr.(type) {case *ast.AsteriskExpression:// 星號表達式:獲取表的所有列allColumns := db.GetAllColumns(stmt.TableName)columns = append(columns, allColumns...)case *ast.Identifier:// 普通列名:獲取單個列column := db.GetColumn(stmt.TableName, expr.Value)columns = append(columns, column)// ... 其他表達式類型}}// ... 繼續執行查詢
}

星號查詢的執行流程

SQL: SELECT * FROM users WHERE age > 18
解析為AST
executeSelect()執行
處理Columns列表
是否為AsteriskExpression?
獲取表的所有列元數據
處理單個列
添加所有列到結果集
應用WHERE過濾條件
返回結果集

4. 星號查詢的AST表示

對于 SELECT * FROM users WHERE age > 18;,完整的AST樹結構如下:

SelectStatement
Columns
TableName: 'users'
Where
AsteriskExpression
BinaryExpression
Left: Identifier{Value: 'age'}
Operator: GREATER
Right: LiteralExpression{Value: '18', Type: NUMBER}

5. 高級應用場景

5.1 表格別名下的星號

表格別名與星號結合使用時,如 SELECT u.* FROM users u,需要特殊處理:

SELECT u.* FROM users u
詞法分析
Token流: [SELECT, u, ., *, FROM, users, u]
解析u.*
創建QualifiedAsteriskExpression
TablePrefix: 'u', Value: '*'

在這種情況下,我們需要一個特殊的AST節點 QualifiedAsteriskExpression 來表示帶表格別名的星號:

// QualifiedAsteriskExpression 表示帶表格別名的星號,如 t.*
type QualifiedAsteriskExpression struct {TablePrefix string // 表前綴,如 t
}func (q *QualifiedAsteriskExpression) expressionNode() {}
func (q *QualifiedAsteriskExpression) TokenLiteral() string { return q.TablePrefix + ".*" }
func (q *QualifiedAsteriskExpression) String() string { return q.TablePrefix + ".*" }

5.2 多表連接中的星號處理

在多表連接中,星號會引入列名沖突問題:

SELECT * FROM users u JOIN orders o ON u.id = o.user_id
解析為AST
執行計劃生成
檢測到多表的*查詢
獲取所有表的列元數據
檢查列名沖突
存在沖突列名?
生成完全限定列名(表名.列名)
保留原列名
構建結果集

在多表連接的例子中,當使用星號時:

  • users 表可能有 id, name, email
  • orders 表可能有 id, user_id, product_id
  • 兩個表都有 id 列,會導致名稱沖突
  • 執行器需要生成如 u.id, o.id 的完全限定名

5.3 星號與列選擇的混合使用

SQL還允許星號與特定列的混合使用,如 SELECT *, extra_column FROM table

SELECT *, created_at FROM users
解析
AST: [AsteriskExpression, Identifier{Value: 'created_at'}]
執行
獲取所有列 + 再次獲取created_at
去重處理
返回結果

這種情況下,執行器需要:

  1. 先獲取所有列
  2. 再處理單獨指定的列
  3. 做重復列的去重處理
  4. 可能需要調整列的順序

6. 性能優化與最佳實踐

星號查詢雖然方便,但存在一些性能和維護方面的注意事項:

6.1 性能影響

查詢性能考慮
SELECT * 查詢
讀取整行數據
增加I/O和內存使用
可能影響索引使用
SELECT 特定列查詢
只讀取需要的列
減少I/O和內存開銷
更有效地利用覆蓋索引

6.2 代碼維護性

使用星號的情況使用具體列名的情況
代碼簡潔代碼明確表達了需要的數據
表結構變更時自動獲取新列不會因表結構變更意外獲取新列
可能獲取不需要的數據只獲取必要數據
列順序依賴表定義列順序由查詢指定
列重命名可能導致代碼錯誤列重命名會導致明確的錯誤

6.3 最佳實踐建議

星號查詢最佳實踐
適用場景
避免場景
折中方案
探索性查詢/調試
需要獲取行的完整信息
ORM自動映射實體
生產環境的高性能查詢
只需少量列的查詢
多表連接查詢
使用表別名限定: t.*
視圖中封裝常用列組合
ORM中配置列映射

7. 實際應用示例

7.1 探索性查詢

在數據探索階段,星號查詢非常實用:

-- 快速了解表結構
SELECT * FROM users LIMIT 10;-- 調試連接查詢
SELECT * FROM orders o JOIN users u ON o.user_id = u.id LIMIT 5;

7.2 與聚合函數結合

星號有時與聚合函數結合使用:

-- 計算總行數
SELECT COUNT(*) FROM users WHERE status = 'active';-- 注意:這里的*是特殊語法,不同于列選擇中的*

這種情況下,COUNT(*)是一種特殊語法,表示"計算行數",而不是"計算所有列"。在解析器中需要特殊處理這種情況。

總結

星號通配符是SQL中最基礎也是最常用的功能之一。盡管語法簡單,但在實現上需要特殊處理,從詞法分析、語法解析到查詢執行的各個環節都有其獨特之處。

通過本文介紹的實現方式,我們的SQL解析器現在完全支持通配符查詢,不僅處理了基本的 SELECT * FROM table 形式,還能正確解析表別名限定的星號和多表連接中的星號用法。這使我們的解析器功能更加完整和實用,為下一步開發查詢執行引擎奠定了基礎。

在實際使用中,應根據具體場景權衡是否使用星號查詢,以在便利性和性能之間取得平衡。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/76413.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76413.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/76413.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

淺析Centos7安裝Oracle12數據庫

Linux下的Oracle數據庫實在是太難安裝了,事賊多,我都懷疑能安裝成功是不是運氣的成分更高一些。這里操作系統是Centos7,Oracle版本是Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production。 Oracle下載鏈接: https…

02-redis-源碼下載

1、進入到官網 redis官網地址https://redis.io/ 2 進入到download頁面 官網頁面往最底下滑動,找到如下頁面 點擊【download】跳轉如下頁面,直接訪問:【https://redis.io/downloads/#stack】到如下頁面 ? 3 找到對應版本的源碼 https…

2024年博客之星的省域空間分布展示-以全網Top300為例

目錄 前言 一、2024博客之星 1、所有排名數據 2、空間屬性管理 二、數據抓取與處理 1、相關業務表的設計 2、數據抓取處理 3、空間查詢分析實踐 三、數據成果挖掘 1、省域分布解讀 2、技術開發活躍 四、總結 前言 2024年博客之星的評選活動已經過去了一個月&#xf…

接口請求控制工具

接口請求控制工具 功能說明代理轉發安全控制訪問控制錯誤處理配置管理日志管理 技術棧快速開始環境要求配置說明啟動服務 工具源碼 功能說明 代理轉發 支持多路由配置支持靜態資源代理靈活的路由規則配置支持請求轉發和響應處理支持負載均衡 支持多目標服務器配置提供多種負載…

Linux: 進程認識(組織進程)

進程認識 (一)馮諾依曼體系結構1.概念從數據流向上理解馮諾依曼 (二)操作系統(OS)1.概念2.設計目的3. 如何理解操作系統的 "管理"4.操作系統調用接口 (三) 進程1.概念2.描述進程-PCB3.如何對PCB進行管理? &a…

回文日期1

#include <iostream> using namespace std;bool isLeap(int y){return (y%40&&y%100!0)||(y%4000); }bool check(int year,int month,int day){//判斷是否為合法日期if(month>12||month0) return false;if(day>31) return false;if(month2){if(isLeap(year…

安寶特案例 | 某戶外機房制造企業應用AR+作業流,規范制造過程,記錄施工節點,保障交付質量

行業特點&#xff1a;產品客制化、依賴人工&#xff0c;工程量大、細節多&#xff0c;驗收困難 戶外通訊機房無疑是現代工業社會的“信息心臟”&#xff0c;承載著信息交換、傳輸與處理的重任。建設一座質量過關的戶外通訊機房是保障通信穩定運行的基石。 通常建設一個戶外通信…

deepseek熱度已過?

DeepSeek的熱度并沒有消退&#xff0c;以下是具體表現&#xff1a; 用戶使用量和下載量方面 ? 日活躍用戶量增長&#xff1a;DeepSeek已經成為目前最快突破3000萬日活躍用戶量的應用程序。 ? 應用商店下載量&#xff1a;1月26日&#xff0c;DeepSeek最新推出的AI聊天機器人…

藍橋杯單片機刷題——通過按鍵觸發串口傳輸電壓值

設計要求 通過內部ADC完成電位器RB2的輸出電壓檢測&#xff0c;并顯示在數碼管上&#xff1b; 通過串口向PC端返回當前檢測的電壓值。 按鍵“S4”定義為發送按鍵&#xff0c;按下按鍵S4&#xff0c;串口向PC端發送當前檢測的電壓值。 串口發送格式&#xff1a; U:1.25V\r\…

DeepSeek 都開源了哪些技術?

DeepSeek作為中國領先的人工智能企業,通過開源策略推動了全球AI技術的普及與創新。以下是其官方公布的主要開源項目及其技術內容、應用場景和社區反饋的詳細分析: 1. FlashMLA 技術描述:專為Hopper架構GPU優化的高效MLA(Multi-Layer Attention)解碼內核,針對可變長度序列…

【北京市小客車調控網站-注冊/登錄安全分析報告】

前言 由于網站注冊入口容易被黑客攻擊&#xff0c;存在如下安全問題&#xff1a; 暴力破解密碼&#xff0c;造成用戶信息泄露短信盜刷的安全問題&#xff0c;影響業務及導致用戶投訴帶來經濟損失&#xff0c;尤其是后付費客戶&#xff0c;風險巨大&#xff0c;造成虧損無底洞…

【SQL Server 2017】封閉網絡下,數據調研所有數據表實戰(提效400%)

?? 點擊關注不迷路 ?? 點擊關注不迷路 ?? 點擊關注不迷路 文章大綱 一、Microsoft SQL Server-2017,環境搭建命令二、借助 @@VERSION 函數來查看當前版本三、查詢Microsoft SQL Server數據庫、表名、表注釋四、所有數據表取樣(SQL生成),查詢前2條數據,數據取樣五、執…

【網絡協議】WebSocket講解

目錄 webSocket簡介 連接原理解析: 客戶端API 服務端API&#xff08;java&#xff09; 實戰案例 &#xff08;1&#xff09;引入依賴 &#xff08;2&#xff09;編寫服務端邏輯 &#xff08;3&#xff09;注冊配置類 &#xff08;4&#xff09;前端連接 WebSocket 示例…

路由器端口映射設置方法教程,和無公網IP內網穿透實現外網訪問方案步驟

隨著網絡技術的不斷發展&#xff0c;越來越多的個人和企業需要將自己的內部服務器或設備暴露給外部網絡訪問。這時&#xff0c;內網端口映射公網技術就顯得尤為重要。下面&#xff0c;我們將分別詳細介紹&#xff0c;有公網IP時如何設置路由器端口映射&#xff0c;和無公網IP內…

Linux 系統中從源碼編譯安裝軟件

以下是 Linux 系統中 從源碼編譯安裝軟件 的詳細步驟和注意事項&#xff0c;幫助你掌握這一高級操作技能&#xff1a; 一、編譯安裝的核心流程 1. 下載源碼包&#xff08;通常為 .tar.gz/.tar.bz2/.tar.xz&#xff09; 2. 解壓源碼包 3. 進入源碼目錄 4. 配置編譯參數&#xf…

HTTP:二.URI及相關術語

HTTP相關技術和術語 WEB開發語言 **http:**Hyper Text Transfer Protocol 應用層協議,默認端口: 80/tcp WEB前端開發語言: htmlcssjavascripthtml Hyper Text Markup Language 超文本標記語言,編程語言,主要負責實現頁面的結構 范例:html 語言 <html> <h…

Java網絡編程干貨

1.網絡編程是什么 了解 在Java語言中&#xff0c;我們可以使用java.net包下的技術輕松開發出常見的網絡應用程序&#xff0c;從而把分布在不同地理區域的計算機與專門的外部設備用通信線路互連成一個規模大、功能強的網絡系統&#x…

Java—HTML:CSS選擇器

今天我要介紹的知識點內容是Java HTML中的CSS選擇器&#xff1b; CSS選擇器用于定位HTML元素并為其添加樣式。它允許我們控制網頁的顏色、字體、布局和其他視覺元素。通過分離內容與樣式。 下面我將介紹CSS中選擇器的使用&#xff0c;并作舉例說明&#xff1b; 選擇器基本語…

【2025藍橋杯】賽前2小時考點梳理C++版

【2025藍橋杯】賽前2小時考點梳理 1. &#x1f9e9; STL&#xff08;優先級最高&#xff09; 核心容器/函數 vector push_back() / pop_back() / size()string substr(pos, len) / find(str) / queue push() / front() / pop()priority_queue 默認大根堆&#xff0c;小根堆&…

汽車性能的幕后保障:慧通測控電動尾翼綜合力學測試淺析

在汽車性能不斷追求極致的當下&#xff0c;電動尾翼已成為眾多高性能車型以及部分新能源汽車提升空氣動力學表現與操控穩定性的關鍵配置。從炫酷的超跑到注重續航與駕駛體驗的新能源車&#xff0c;電動尾翼正逐漸嶄露頭角。它絕非僅僅是外觀上的裝飾&#xff0c;而是能在車輛行…