sqlglot

sqlglot

SQL解析转译优化和执行引擎

SQLGlot是一个功能全面的SQL工具,支持解析、转译、优化和执行SQL。它可以在21种SQL方言间转换,包括DuckDB、Presto和Spark等。SQLGlot能够处理多种SQL输入,并生成符合目标方言语法和语义的SQL输出。该工具采用纯Python实现,具有出色的性能和完善的测试。SQLGlot还支持自定义解析、查询分析、表达式树遍历和编程式SQL构建等高级功能。

SQLGlotSQL解析器SQL转译器SQL优化器SQL引擎Github开源项目

SQLGlot标志

SQLGlot是一个无依赖的SQL解析器、转译器、优化器和引擎。它可以用于格式化SQL或在21种不同的方言之间进行转换,如DuckDBPresto / TrinoSpark / DatabricksSnowflakeBigQuery。它旨在读取各种SQL输入,并在目标方言中输出语法和语义正确的SQL。

它是一个非常全面的通用SQL解析器,具有强大的测试套件。它也相当高性能,同时完全用Python编写。

你可以轻松地自定义解析器,分析查询,遍历表达式树,以及以编程方式构建 SQL。

语法错误会被突出显示,方言不兼容可以根据配置发出警告或引发异常。然而,SQLGlot并不旨在成为一个SQL验证器,因此可能无法检测某些语法错误。

在API文档和表达式树入门指南中了解更多关于SQLGlot的信息。

SQLGlot非常欢迎贡献;阅读贡献指南开始吧!

目录

安装

从PyPI安装:

pip3 install "sqlglot[rs]" # 不带Rust分词器(较慢): # pip3 install sqlglot

或本地checkout:

make install

开发要求(可选):

make install-dev

版本控制

给定版本号MAJOR.MINOR.PATCH,SQLGlot使用以下版本策略:

  • 当有向后兼容的修复或功能添加时,增加PATCH版本。
  • 当有向后不兼容的修复或功能添加时,增加MINOR版本。
  • 当有重大的向后不兼容的修复或功能添加时,增加MAJOR版本。

联系我们

我们很乐意听到你的声音。加入我们的社区Slack频道

常见问题

我尝试解析应该有效的SQL但失败了,为什么会这样?

  • 大多数情况下,这种问题发生是因为在解析过程中省略了"源"方言。例如,这是正确解析用Spark SQL编写的SQL查询的方法:parse_one(sql, dialect="spark")(或者:read="spark")。如果未指定方言,parse_one将尝试根据"SQLGlot方言"解析查询,该方言旨在成为所有支持的方言的超集。如果你尝试指定方言后仍然不起作用,请提交一个问题。

我尝试输出SQL但它不是正确的方言!

  • 与解析一样,生成SQL也需要指定目标方言,否则默认将使用SQLGlot方言。例如,要将查询从Spark SQL转译为DuckDB,执行parse_one(sql, dialect="spark").sql(dialect="duckdb")(或者:transpile(sql, read="spark", write="duckdb"))。

我尝试解析无效的SQL,它成功了,尽管应该引发错误!为什么它没有验证我的SQL?

  • SQLGlot并不旨在成为一个SQL验证器 - 它被设计得非常宽容。这使得代码库更加全面,也为用户提供了更多灵活性,例如允许他们在投影列表中包含尾随逗号。

sqlglot.dataframe发生了什么?

  • PySpark数据框API在第24版中被移到了一个独立的库SQLFrame中。它现在允许你运行查询,而不仅仅是生成SQL。

示例

格式化和转译

轻松地从一种方言转换到另一种方言。例如,日期/时间函数在不同方言之间有所不同,可能很难处理:

import sqlglot sqlglot.transpile("SELECT EPOCH_MS(1618088028295)", read="duckdb", write="hive")[0]
'SELECT FROM_UNIXTIME(1618088028295 / POW(10, 3))'

SQLGlot甚至可以转换自定义时间格式:

import sqlglot sqlglot.transpile("SELECT STRFTIME(x, '%y-%-m-%S')", read="duckdb", write="hive")[0]
"SELECT DATE_FORMAT(x, 'yy-M-ss')"

标识符分隔符和数据类型也可以被转换:

import sqlglot # Spark SQL要求使用反引号(`)作为分隔标识符,并使用`FLOAT`而不是`REAL` sql = """WITH baz AS (SELECT a, c FROM foo WHERE a = 1) SELECT f.a, b.b, baz.c, CAST("b"."a" AS REAL) d FROM foo f JOIN bar b ON f.a = b.a LEFT JOIN baz ON f.a = baz.a""" # 将查询转译为Spark SQL,格式化它,并分隔所有标识符 print(sqlglot.transpile(sql, write="spark", identify=True, pretty=True)[0])
WITH `baz` AS ( SELECT `a`, `c` FROM `foo` WHERE `a` = 1 ) SELECT `f`.`a`, `b`.`b`, `baz`.`c`, CAST(`b`.`a` AS FLOAT) AS `d` FROM `foo` AS `f` JOIN `bar` AS `b` ON `f`.`a` = `b`.`a` LEFT JOIN `baz` ON `f`.`a` = `baz`.`a`

注释也会尽最大努力保留:

sql = """ /* 多 注释 */ SELECT tbl.cola /* 注释1 */ + tbl.colb /* 注释2 */, CAST(x AS SIGNED), # 注释3 y -- 注释4 FROM bar /* 注释5 */, tbl # 注释6 """ # 注意:MySQL特定的注释(`#`)被转换为标准语法 print(sqlglot.transpile(sql, read='mysql', pretty=True)[0])
/* 多 注释 */ SELECT tbl.cola /* 注释1 */ + tbl.colb /* 注释2 */, CAST(x AS INT), /* 注释3 */ y /* 注释4 */ FROM bar /* 注释5 */, tbl /* 注释6 */

元数据

你可以使用表达式辅助函数探索SQL,做一些事情,比如在查询中查找列和表:

from sqlglot import parse_one, exp # 打印所有列引用(a和b) for column in parse_one("SELECT a, b + 1 AS c FROM d").find_all(exp.Column): print(column.alias_or_name) # 在select语句中查找所有投影(a和c) for select in parse_one("SELECT a, b + 1 AS c FROM d").find_all(exp.Select): for projection in select.expressions: print(projection.alias_or_name) # 查找所有表(x,y,z) for table in parse_one("SELECT * FROM x JOIN y JOIN z").find_all(exp.Table): print(table.name)

阅读ast入门指南以了解更多关于SQLGlot内部结构的信息。

解析器错误

当解析器检测到语法错误时,它会引发一个ParseError

import sqlglot sqlglot.transpile("SELECT foo FROM (SELECT baz FROM t")
sqlglot.errors.ParseError: 期望)。第1行,第34列。
  SELECT foo FROM (SELECT baz FROM t
                                   ~

结构化的语法错误可用于程序化使用:

import sqlglot try: sqlglot.transpile("SELECT foo FROM (SELECT baz FROM t") except sqlglot.errors.ParseError as e: print(e.errors)
[{ 'description': '期望)', 'line': 1, 'col': 34, 'start_context': 'SELECT foo FROM (SELECT baz FROM ', 'highlight': 't', 'end_context': '', 'into_expression': None }]

不支持错误

在某些方言之间可能无法转换某些查询。在这些情况下,SQLGlot可能会发出警告,并默认继续进行尽力而为的转换:

import sqlglot sqlglot.transpile("SELECT APPROX_DISTINCT(a, 0.1) FROM foo", read="presto", write="hive")
APPROX_COUNT_DISTINCT不支持精度 'SELECT APPROX_COUNT_DISTINCT(a) FROM foo'

可以通过设置unsupported_level属性来改变这种行为。例如,我们可以将其设置为RAISEIMMEDIATE以确保引发异常:

import sqlglot sqlglot.transpile("SELECT APPROX_DISTINCT(a, 0.1) FROM foo", read="presto", write="hive", unsupported_level=sqlglot.ErrorLevel.RAISE)
sqlglot.errors.UnsupportedError: APPROX_COUNT_DISTINCT不支持精度

有些查询需要额外的信息才能准确转译,比如引用的表的架构。这是因为某些转换是类型敏感的,这意味着需要类型推断来理解它们的语义。尽管qualifyannotate_types优化器规则可以帮助解决这个问题,但它们默认不被使用,因为它们会增加显著的开销和复杂性。

转译通常是一个困难的问题,所以SQLGlot采用"增量"方法来解决它。这意味着目前可能存在一些方言对无法支持某些输入,但预计随着时间的推移会有所改善。我们非常感谢有良好文档和测试的问题或PR,如果你需要指导,请随时联系我们

构建和修改SQL

SQLGlot支持增量构建SQL表达式:

from sqlglot import select, condition where = condition("x=1").and_("y=1") select("*").from_("y").where(where).sql()
'SELECT * FROM y WHERE x = 1 AND y = 1'

可以修改已解析的树:

from sqlglot import parse_one parse_one("SELECT x FROM y").from_("z").sql()
'SELECT x FROM z'

还可以通过对树中的每个节点应用映射函数来递归转换已解析的表达式:

from sqlglot import exp, parse_one expression_tree = parse_one("SELECT a FROM x") def transformer(node): if isinstance(node, exp.Column) and node.name == "a": return parse_one("FUN(a)") return node transformed_tree = expression_tree.transform(transformer) transformed_tree.sql()
'SELECT FUN(a) FROM x'

SQL优化器

SQLGlot可以将查询重写为"优化"形式。它执行各种技术来创建一个新的规范AST。这个AST可以用来标准化查询或为实现实际引擎提供基础。例如:

import sqlglot from sqlglot.optimizer import optimize print( optimize( sqlglot.parse_one(""" SELECT A OR (B OR (C AND D)) FROM x WHERE Z = date '2021-01-01' + INTERVAL '1' month OR 1 = 0 """), schema={"x": {"A ```python [ Remove(expression=Add( this=Column( this=Identifier(this=a, quoted=False)), expression=Column( this=Identifier(this=b, quoted=False)))), Insert(expression=Sub( this=Column( this=Identifier(this=a, quoted=False)), expression=Column( this=Identifier(this=b, quoted=False)))), Keep( source=Column(this=Identifier(this=a, quoted=False)), target=Column(this=Identifier(this=a, quoted=False))), ... ]

另见:SQL语义差异

自定义方言

可以通过继承Dialect来添加方言:

from sqlglot import exp from sqlglot.dialects.dialect import Dialect from sqlglot.generator import Generator from sqlglot.tokens import Tokenizer, TokenType class Custom(Dialect): class Tokenizer(Tokenizer): QUOTES = ["'", '"'] IDENTIFIERS = ["`"] KEYWORDS = { **Tokenizer.KEYWORDS, "INT64": TokenType.BIGINT, "FLOAT64": TokenType.DOUBLE, } class Generator(Generator): TRANSFORMS = {exp.Array: lambda self, e: f"[{self.expressions(e)}]"} TYPE_MAPPING = { exp.DataType.Type.TINYINT: "INT64", exp.DataType.Type.SMALLINT: "INT64", exp.DataType.Type.INT: "INT64", exp.DataType.Type.BIGINT: "INT64", exp.DataType.Type.DECIMAL: "NUMERIC", exp.DataType.Type.FLOAT: "FLOAT64", exp.DataType.Type.DOUBLE: "FLOAT64", exp.DataType.Type.BOOLEAN: "BOOL", exp.DataType.Type.TEXT: "STRING", } print(Dialect["custom"])
<class '__main__.Custom'>

SQL执行

SQLGlot能够解释SQL查询,其中表以Python字典的形式表示。该引擎并不是为了追求速度,但它对单元测试和在Python对象上原生运行SQL很有用。此外,这个基础可以轻松地与快速计算内核集成,如ArrowPandas

下面的例子展示了执行一个涉及聚合和连接的查询:

from sqlglot.executor import execute tables = { "sushi": [ {"id": 1, "price": 1.0}, {"id": 2, "price": 2.0}, {"id": 3, "price": 3.0}, ], "order_items": [ {"sushi_id": 1, "order_id": 1}, {"sushi_id": 1, "order_id": 1}, {"sushi_id": 2, "order_id": 1}, {"sushi_id": 3, "order_id": 2}, ], "orders": [ {"id": 1, "user_id": 1}, {"id": 2, "user_id": 2}, ], } execute( """ SELECT o.user_id, SUM(s.price) AS price FROM orders o JOIN order_items i ON o.id = i.order_id JOIN sushi s ON i.sushi_id = s.id GROUP BY o.user_id """, tables=tables )
user_id price 1 4.0 2 3.0

另见:从零开始编写Python SQL引擎

使用者

文档

SQLGlot使用pdoc来提供其API文档。

托管版本在SQLGlot网站上,或者你可以通过以下命令在本地构建:

make docs-serve

运行测试和代码检查

make style  # 仅运行代码检查
make unit   # 仅运行单元测试(或使用unit-rs来使用Rust分词器)
make test   # 单元和集成测试(或使用test-rs来使用Rust分词器)
make check  # 完整的测试套件和代码检查

基准测试

基准测试在Python 3.10.12上运行,单位为秒。

查询sqlglotsqlglotrssqlfluffsqltreesqlparsemoz_sql_parsersqloxide
tpch0.00944 (1.0)0.00590 (0.625)0.32116 (33.98)0.00693 (0.734)0.02858 (3.025)0.03337 (3.532)0.00073 (0.077)
short0.00065 (1.0)0.00044 (0.687)0.03511 (53.82)0.00049 (0.759)0.00163 (2.506)0.00234 (3.601)0.00005 (0.073)
long0.00889 (1.0)0.00572 (0.643)0.36982 (41.56)0.00614 (0.690)0.02530 (2.844)0.02931 (3.294)0.00059 (0.066)
crazy0.02918 (1.0)0.01991 (0.682)1.88695 (64.66)0.02003 (0.686)7.46894 (255.9)0.64994 (22.27)0.00327 (0.112)

可选依赖

SQLGlot使用dateutil来简化字面时间间隔表达式。如果找不到该模块,优化器将不会简化像下面这样的表达式:

x + interval '1' month

编辑推荐精选

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

热门AI开发模型训练AI工具讯飞星火大模型智能问答内容创作多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

Trae

Trae

字节跳动发布的AI编程神器IDE

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
咔片PPT

咔片PPT

AI助力,做PPT更简单!

咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。

讯飞绘文

讯飞绘文

选题、配图、成文,一站式创作,让内容运营更高效

讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。

热门AI辅助写作AI工具讯飞绘文内容运营AI创作个性化文章多平台分发AI助手
材料星

材料星

专业的AI公文写作平台,公文写作神器

AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。

openai-agents-python

openai-agents-python

OpenAI Agents SDK,助力开发者便捷使用 OpenAI 相关功能。

openai-agents-python 是 OpenAI 推出的一款强大 Python SDK,它为开发者提供了与 OpenAI 模型交互的高效工具,支持工具调用、结果处理、追踪等功能,涵盖多种应用场景,如研究助手、财务研究等,能显著提升开发效率,让开发者更轻松地利用 OpenAI 的技术优势。

Hunyuan3D-2

Hunyuan3D-2

高分辨率纹理 3D 资产生成

Hunyuan3D-2 是腾讯开发的用于 3D 资产生成的强大工具,支持从文本描述、单张图片或多视角图片生成 3D 模型,具备快速形状生成能力,可生成带纹理的高质量 3D 模型,适用于多个领域,为 3D 创作提供了高效解决方案。

3FS

3FS

一个具备存储、管理和客户端操作等多种功能的分布式文件系统相关项目。

3FS 是一个功能强大的分布式文件系统项目,涵盖了存储引擎、元数据管理、客户端工具等多个模块。它支持多种文件操作,如创建文件和目录、设置布局等,同时具备高效的事件循环、节点选择和协程池管理等特性。适用于需要大规模数据存储和管理的场景,能够提高系统的性能和可靠性,是分布式存储领域的优质解决方案。

下拉加载更多