Я работаю над инструментом анализа 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
в запросе, переформатируя исходный ввод для удаления подзапросов в соответствии с желаемым выходным образцом.