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.mzph.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;而是能在车辆行…