Форматирование SQL-запроса

У меня есть входная строка, которая является SQL-запросом. Мне нужно получить все таблицы, которые использует запрос (например, FROM стол или Таблица 1 INNER JOIN Таблица 2). Но запрос не соответствует ни одному стандарту. Поэтому мой вопрос заключается в том, есть ли какой-либо способ форматирования запроса, чтобы упростить поиск этих имен таблиц.

Мой метод прямо сейчас состоит в том, чтобы искать ключевые слова из и соединять и брать любую строку после ключевого слова (или перед в случае соединения), но есть исключения в запросах, где из нет новой строки после него и Я должен обрабатывать каждое исключение таким образом. Я не думаю, что регулярное выражение работает, потому что хотя имя таблицы {schema_name.table_name}, есть и такие столбцы.

for row in text:
    to_append = None
    split_row = row.strip('\r').strip(' ').strip('\r').split(' ')
    if split_row[-1].lower() == "from" and len(split_row) > 1:
        from_indexes.append(text.index(row))
    if ("join" in split_row or "JOIN" in split_row) and (split_row[-1] != "join" and split_row[-1]
                                                         != "JOIN"):
        for ind in range(len(split_row)):
            if split_row[ind].lower() == "join":
                to_append = split_row[ind + 1:]
                row = split_row[:ind + 1]
                row = ' '.join(row)
    rows.append(row.strip('\r').strip(' ').strip('\t'))
    if to_append is not None:
        rows.append(' '.join(to_append))

Поэтому я ищу какой-нибудь метод, который может стандартизировать запрос sql или другой метод для извлечения имен таблиц из запроса.

почему ты хочешь сделать это? это очень неудобно в общем случае, например. что вы должны получить в ответ WITH x AS (SELECT 'SELECT 1 FROM foo' AS y) SELECT * FROM x;?

Sam Mason 24.06.2019 12:55

Если и foo, и x не являются временными таблицами, мне нужны и foo, и x.

Andrei 24.06.2019 14:26

это был риторический вопрос! x — это CTE, следовательно, это не «настоящая» таблица, но она может быть интересна в зависимости от того, что вы пытаетесь сделать. foo — это фрагмент текста, встроенный в строку, поэтому его почти наверняка следует игнорировать любым разумным инструментом. если вы пишете код для разбора SQL, это стандартные проблемы, о которых вам нужно подумать и решить

Sam Mason 24.06.2019 14:32

Я создаю приложение, которое находит зависимости таблиц в других базах данных. В одной из таблиц есть метаданные, включая столбец с запросами sql и невременные таблицы после ключевого слова from/join, которые рассматриваются как зависимости, поэтому мне нужно анализировать SQL.

Andrei 24.06.2019 14:56
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
4
107
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы должны использовать инструмент ORM, чтобы делать более чистые запросы (см. https://en.wikipedia.org/wiki/Object-relational_mapping). Или, по крайней мере, некоторые модули построения запросов.

Недавно я нашел ремейк laravels "reloquent" orm здесь https://pypi.org/project/eloquent/.

Другие ORM, такие как PeeWee, также довольно распространены.

Я не делаю запросы. У меня нет возможности их изменить.

Andrei 24.06.2019 12:35
Ответ принят как подходящий

Я думаю, что более простым подходом было бы использование регулярные выражения:

import re

sql = """select t1.*, t2.y, sq.z, table3.q from table1 t1 join
    table2 t2 on t1.x = t2.x left join
    (select 5 as x, 9 as z) sq JOIN
    table3 on sq.x = table3.x
;"""

matches = re.findall(r'(\s+(from|join)\s+)(\w+)', sql, re.DOTALL|re.IGNORECASE)
for match in matches:
    print(match[2])

Обратите внимание, что он не будет рассматривать (выберите 5 как x, 9 как z) как таблицу.

Кажется, это ответ. Работает намного лучше, чем мой алгоритм. Спасибо.

Andrei 24.06.2019 14:50

Затем вы должны пометить ответ как «принятый», если и когда вы считаете, что это уместно. См. Что мне делать, когда кто-то отвечает на мой вопрос?.

Booboo 24.06.2019 15:01

Другие вопросы по теме