Регулярное выражение для извлечения SQL-запроса

Есть ли регулярное выражение, которое извлекает SQL-запросы из строки? Я НЕ, заинтересованный в проверке любого синтаксиса SQL, а не только на выбор команд SQL. Это позволяет гибко анализировать данный файл/строку SQL.

Ниже представлен следующий пример файла SQL/string:

SELECT
 *
FROM
 test_table
WHERE
 test_row = 'Testing ; semicolon';
SELECT * FROM another_test_table;
INSERT INTO 
 table_name 
VALUES 
 (value1,'value which contains semicolon ;;;;',value3,...);

Некоторый пример псевдокода: ^(UPDATE|SELECT|INSERT INTO)(.*)(;)$. В будущем я хочу расширить это с помощью всех (возможных) команд.

  • Ищите начальное совпадение с: (UPDATE | SELECT | INSERT | INTO)
  • Ноль или более any character (включая пробелы и символы новой строки)
  • Остановить на ;, который ограничивает SQL-запрос.

Всякий раз, когда это возможно с помощью регулярного выражения, следующий код java может извлекать все команды SQL:

final String regex = "LOOKING_FOR_THIS_ONE";
final Pattern p = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = p.matcher(content);
while (matcher.find()) {
 // matcher.group() now contains the full SQL command
}

Спасибо заранее!

5 ответов

Я начну, сказав, что это не очень хороший способ сделать это, и настоятельно призываю вас найти другой способ сделать это, предпочтительно пометить его правильно там, где сделаны заявления, чтобы вы не закончили в этой ситуации.

При этом SQL требует, чтобы он начинался с одного из следующих: DELETE, SELECT, WITH, UPDATE или INSERT INTO. Он также требует, чтобы вход заканчивался на ;.

Мы можем использовать это, чтобы захватить все последовательности, соответствующие SQL, следующим образом:

final String regex = "^(INSERT INTO|UPDATE|SELECT|WITH|DELETE)(?:[^;']|(?:'[^']+'))+;\\s*$";
final Pattern p = Pattern.compile(regex, Pattern.MULTILINE | Pattern.DOTALL);

В группе 1 теперь выполняется операционное слово, если вы хотите отфильтровать действительный SQL на UPDATE или SELECT.

Смотрите регулярное выражение в действии, а также пещеру здесь:

https://regex101.com/r/dt9XTK/2


Вы можете сопоставить его "правильно", если точка с запятой является последним символом без пробела в этой строке.

final String regex = ^(SELECT|UPDATE|INSERT)[\s\S]+?\;\s*?$
final Pattern p = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = p.matcher(content);


Если вы имеете дело с языком, создайте лексер, который символизирует вашу строку. Используйте JFlex, который является генератором лексического анализатора. Он генерирует класс Java, который разбивает строку на токены на основе грамматики, заданной в специальном файле. Возьмите соответствующие правила грамматики из этот файл.

Анализ - это отдельный процесс, чем токенизация (или лексический анализ). Возможно, вы захотите использовать генератор парсера после лексического анализа, если лексического анализа недостаточно.


SQL достаточно сложна, что вам понадобится контекст для поиска всех операторов, что означает, что вы не можете сделать это с помощью регулярного выражения.

Например:

SELECT Model FROM Product
WHERE ManufacturerID IN (SELECT ManufacturerID FROM Manufacturer 
WHERE Manufacturer = 'Dell')

(пример получен из http://www.sql-tutorial.com/sql-nested-queries-sql-tutorial/). Вложенные запросы могут вставляться несколько раз, начинать с разных значений и т.д. Если вы могли бы написать регулярное выражение для интересующего вас подмножества, оно было бы нечитаемым.

ANTLR имеет грамматику SQL 2003 (Я не пробовал).


(?m)^(UPDATE|SELECT|INSERT INTO).*;$ должен работать. Это расширит шаблон, чтобы он соответствовал символам новой строки. Он должен иметь возможность прокручивать и находить все ваши SQL.

Глядя на приведенный вами пример, он будет соответствовать вашим командам до ;. Вы можете увидеть пример, используемый для тестирования здесь.

licensed under cc by-sa 3.0 with attribution.