SQLGlot 是一个无依赖的 Python SQL 解析器、转译器和优化器。
SQLGlot 是一个无依赖的 Python SQL 解析器、转译器和优化器。它可用于格式化 SQL 或在DuckDB、Presto、Spark和BigQuery等不同方言之间进行转换。它旨在读取各种 SQL 输入并以目标方言输出语法正确的 SQL。
它是一个非常全面的通用 SQL 解析器,具有强大的测试套件。它在纯粹用 Python 编写时也非常高效。
您可以轻松自定义解析器、分析查询、遍历表达式树以及以编程方式构建SQL。
语法错误会突出显示,并且方言不兼容可能会根据配置发出警告或引发。
安装
来自 PyPI
pip3 install sqlglot
或使用本地结帐
pip3 install -e .
例子
轻松地从一种方言翻译成另一种方言。例如,日期/时间函数因方言不同而难以处理。
import sqlglot sqlglot.transpile("SELECT EPOCH_MS(1618088028295)", read='duckdb', write='hive')
SELECT TO_UTC_TIMESTAMP(FROM_UNIXTIME(1618088028295 / 1000, 'yyyy-MM-dd HH:mm:ss'), 'UTC')
SQLGlot 甚至可以转换自定义时间格式。
import sqlglot sqlglot.transpile("SELECT STRFTIME(x, '%y-%-m-%S')", read='duckdb', write='hive')
SELECT DATE_FORMAT(x, 'yy-M-ss')"
格式化和转译
读入带有 CTE 和 CASTING 的 SQL 语句到 REAL,然后转译到 Spark。
Spark 使用反引号作为标识符,并将 REAL 类型转换为 FLOAT。
import sqlglot 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""" 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 来执行查找列和表等操作。
from sqlglot import parse_one, exp # print all column references (a and b) for column in parse_one("SELECT a, b + 1 AS c FROM d").find_all(exp.Column): print(column.alias_or_name) # find all projections in select statements (a and 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) # find all tables (x, y, z) for table in parse_one("SELECT * FROM x JOIN y JOIN z").find_all(exp.Table): print(table.name)
解析器错误
语法错误将导致解析器错误。
transpile("SELECT foo( FROM bar")
sqlglot.errors.ParseError:期待)。第 1 行,列:13. select foo( FROM bar
不支持的错误
Presto APPROX_DISTINCT 支持 Spark 中不支持的准确度参数。
transpile( 'SELECT APPROX_DISTINCT(a, 0.1) FROM foo', read='presto', write='spark', )
WARNING:root:APPROX_COUNT_DISTINCT does not support accuracy SELECT APPROX_COUNT_DISTINCT(a) FROM foo
构建和修改 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 y, 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 >>> 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": "INT", "B": "INT", "C": "INT", "D": "INT", "Z": "STRING"}} ).sql(pretty=True) """ SELECT ( "x"."A" OR "x"."B" OR "x"."C" ) AND ( "x"."A" OR "x"."B" OR "x"."D" ) AS "_col_0" FROM "x" AS "x" WHERE "x"."Z" = CAST('2021-02-01' AS DATE) """