解析 SQL 子查询的简单方法
Simple way to parse SQL subqueries
我正在开发一个 SQL 分析工具,给定一个 RAW SQL SELECT 查询,它可以提供某种分析。该工具的第一个版本已经完成,可以分析简单的 RAW 查询。但是,当查询包含子查询时,它会中断。
所以我正在寻找一种简单但可靠的方法来解析查询和子查询。我的工具必须单独分析每个子查询,例如:
假设这是该工具作为输入给出的查询:
SELECT name, email
FROM (SELECT * FROM user WHERE email IS NOT NULL)
WHERE id IN (SELECT cID FROM customer WHERE points > 5)
然后我想得到一个这样的查询列表:
queries = [
"SELECT name, EMAIL FROM <subquery> WHERE id in <subquery>"
"SELECT * FROM user WHERE email IS NOT NULL"
"SELECT cID FROM customer WHERE points > 5)"
]
在我的第一次尝试中,我使用了子查询总是写在括号之间的事实。所以我扫描括号的初始查询。这在子查询未嵌套时有效,即子查询内没有子查询。我也尝试了一下 AST,但觉得它可能有点太复杂了,可能还有更简单的方法。
谁能指导我正确的方向?我正在使用 Python,但也非常感谢其他语言的示例。
您可以使用 sqlparse
:
import sqlparse
def queries(d):
if type(d) != sqlparse.sql.Token:
paren = isinstance(d, sqlparse.sql.Parenthesis)
v = [queries(i) for i in (d if not paren else d[1:-1])]
subseq, qrs = ''.join(str(i[0]) for i in v), [x for _, y in v for x in y]
if [*d][paren].value == 'SELECT':
return '<subquery>', [subseq]+qrs
return subseq, qrs
return d, []
s="""SELECT name, email
FROM (SELECT * FROM user WHERE email IS NOT NULL)
WHERE id IN (SELECT cID FROM customer WHERE points > 5)
"""
_, subqueries = queries(sqlparse.parse(s)[0])
输出:
['SELECT name, email\n FROM <subquery>\n WHERE id IN <subquery>\n', 'SELECT * FROM user WHERE email IS NOT NULL', 'SELECT cID FROM customer WHERE points > 5']
使用 sqlparse
库,您可以将 SQL 输入字符串解析为关键字、语句和值的标记化流。上面的函数 queries
接受一个 sqlparse.sql.Statement
对象并搜索查询中任何出现的 SELECT
语句,根据所需的输出样本重新格式化原始输入以删除子查询.
我正在开发一个 SQL 分析工具,给定一个 RAW SQL SELECT 查询,它可以提供某种分析。该工具的第一个版本已经完成,可以分析简单的 RAW 查询。但是,当查询包含子查询时,它会中断。
所以我正在寻找一种简单但可靠的方法来解析查询和子查询。我的工具必须单独分析每个子查询,例如:
假设这是该工具作为输入给出的查询:
SELECT name, email
FROM (SELECT * FROM user WHERE email IS NOT NULL)
WHERE id IN (SELECT cID FROM customer WHERE points > 5)
然后我想得到一个这样的查询列表:
queries = [
"SELECT name, EMAIL FROM <subquery> WHERE id in <subquery>"
"SELECT * FROM user WHERE email IS NOT NULL"
"SELECT cID FROM customer WHERE points > 5)"
]
在我的第一次尝试中,我使用了子查询总是写在括号之间的事实。所以我扫描括号的初始查询。这在子查询未嵌套时有效,即子查询内没有子查询。我也尝试了一下 AST,但觉得它可能有点太复杂了,可能还有更简单的方法。
谁能指导我正确的方向?我正在使用 Python,但也非常感谢其他语言的示例。
您可以使用 sqlparse
:
import sqlparse
def queries(d):
if type(d) != sqlparse.sql.Token:
paren = isinstance(d, sqlparse.sql.Parenthesis)
v = [queries(i) for i in (d if not paren else d[1:-1])]
subseq, qrs = ''.join(str(i[0]) for i in v), [x for _, y in v for x in y]
if [*d][paren].value == 'SELECT':
return '<subquery>', [subseq]+qrs
return subseq, qrs
return d, []
s="""SELECT name, email
FROM (SELECT * FROM user WHERE email IS NOT NULL)
WHERE id IN (SELECT cID FROM customer WHERE points > 5)
"""
_, subqueries = queries(sqlparse.parse(s)[0])
输出:
['SELECT name, email\n FROM <subquery>\n WHERE id IN <subquery>\n', 'SELECT * FROM user WHERE email IS NOT NULL', 'SELECT cID FROM customer WHERE points > 5']
使用 sqlparse
库,您可以将 SQL 输入字符串解析为关键字、语句和值的标记化流。上面的函数 queries
接受一个 sqlparse.sql.Statement
对象并搜索查询中任何出现的 SELECT
语句,根据所需的输出样本重新格式化原始输入以删除子查询.