миниПарсер SQL запросов

Рейтинг: 2Ответов: 1Опубликовано: 28.04.2015

Нужно вытащить названия основных таблиц Select ... From TableName Имеются запросы четырёх типов:

1. Select ... From TableName

2. Select ... From Only TableName

3. Select ... From TableName1
   Union
   Select ... From TableName2

4. Select ...,
     Exists(SELECT true FROM _tName WHERE ...)
   From TableName

Написал регулярку: (с параметрами gims тестил тут) (запросы страшние с множественными переносами строк, табуляторами и пробелами, потому вставлял везде \s\t\r\n)

(?:[\s\t\r\n]*select.+?from[\s\t\r\n]*(?:only|)[\s\t\r\n]*)(\S*)

Обламывается на 4ом примере, как учесть в ней подзапросы? Например, чтобы выбирала только Select..From между которыми нет ещё одного Select. Если просто делать жадным, то не находятся все таблицы при Union

Ответы

▲ 4Принят

Решается банальной рекурсией в регулярном выражении.
Извините за странное написание. Привычка.

(?P<onlyselect>\bselect\s*.*?\bfrom\s*+(?:only)?\s*+\S++){0}\bselect\s*(?:(?P>onlyselect)|.)*?\bfrom\s*+(?:only)?\s*+(\S++) 
# IGNORECASE DOTALL

Входящий текст:

1. Select ...
 From TableName1

2. Select ... From Only TableName2

3. Select ... From TableName3
   Union
   Select ... From TableName4

4. Select ...,
     Exists(SELECT true FROM TableName5 WHERE ...)
   From TableName6

Результат:

MATCH 1
2.  [20-30] `TableName1`
MATCH 2
2.  [56-66] `TableName2`
MATCH 3
2.  [87-97] `TableName3`
MATCH 4
2.  [126-136]   `TableName4`
MATCH 5
2.  [212-222]   `TableName6`

https://regex101.com/r/pK5xW3/3
P.S. Регулярное выражение не учитывает комментарии, CDATA и прочие прелести SQL-запросов. Оно просто решает задачу, поставленную в вопросе.