Использование регулярных выражений для сканирования T-SQL на предметные зависимости - PullRequest
2 голосов
/ 04 декабря 2011

Я пишу библиотеку классов ac #, которая позволит мне сканировать запрос сервера SQL и извлекать объекты из запроса в их правильные группировки, например:

SELECT * FROM "My Server"."Northwind"."dbo"."Product Sales for 1997" Group By CategoryID

Это регулярное выражение будет соответствовать приведенному вышеСтрока и группа «Мой сервер», «Northwind», «dbo» и «Продажи продуктов за 1997 год» в четыре группы, и это то, что я хочу.

(?i)\bFROM\b\s+[\["]([^\]"]*)[\]"].{1}[\["]([^\]"]*)[\]"].{1}[\["]([^\]"]*)[\]"].{1}[\["]([^\]"]*)[\]"].{1}

Я ищу только одно регулярное выражениевыражение, которое может захватывать имя сервера, имя базы данных, имя схемы и имя объекта для любой из следующих комбинаций (это не исчерпывающий список любыми способами):

SELECT * FROM dbo."Product Sales for 1997" // should return groups 2 & 3
SELECT * FROM Northwind."My Schema"."My view or table function" // should return  groups 1, 2 & 3
SELECT * FROM "My view or table function" // should return group 3
SELECT * FROM dbo."My View 1" AS V1 JOIN "My View 1" AS V2 ON V1.ID = V2 // should return groups 2 & 3

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

Группа 0 -> Имя сервераГруппа 1 -> Имя базы данныхГруппа 2 -> СхемаГруппа 3 -> Имя объекта

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

Ответы [ 2 ]

0 голосов
/ 10 января 2012

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

С помощью полноценного синтаксического анализатора SQL довольно легко добиться того, что вам нужно:

SELECT * FROM Northwind."My Schema"."My view or table function";

вывод будетбыть примерно таким:

select clause:
Columns
Fullname:*
Prefix: Column:*    alias:

from clause:
   Northwind."My Schema"."My view or table function"

database: Northwind
schema:   "My Schema"
object:   "My view or table function"
object alias:

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

0 голосов
/ 17 декабря 2011

Лучшее, что можно сделать с регулярным выражением, - это разобрать его в токены, и тогда нужно будет определить, каковы действительные значения (база данных сервера и т. Д.) Групп.Вот регулярное выражение для добавления ваших примеров данных в такие токены.Заметьте, я не знал, что на сервере sql были кавычки, но в вашем примере их попросили, поэтому я ищу одинарные и двойные кавычки, экранированные как \ x22 и \ x27, соответственно, используя условное условие If (см. Статью моего блога Регулярные выражения иЕсли условно ).Жетоны помещаются в захваты матчей, где они извлекаются.

string data =
@"SELECT * FROM dbo.""Product Sales for 1997"" // should return groups 2 & 3 
SELECT * FROM Northwind.""My Schema"".""My view or table function"" // should return  groups 1, 2 & 3 
SELECT * FROM ""My view or table function"" // should return group 3 
SELECT * FROM dbo.""My View 1"" AS V1 JOIN ""My View 1"" AS V2 ON V1.ID = V2 // should return groups 2 & 3 ";

string pattern = 
@"
(?:FROM\s+)                 # Work from a from only
(
  (?([\x27\x22])            # If a single or double quote is found      
     (?:[\x27\x22])
       (?<Tokens>[\w\s]+)   # process quoted text
     (?:[\x27\x22]\.?)
   |                        # else
     (?!\s+AS|\s+WHERE)     # if AS or Where is found stop the match we are done
     (?:\.?)
     (?<Tokens>\w+)         # Process non quoted token.
     (?:\.?)
   )
   (?![\n\r/])              # Stop on CR/LF or a comment. 
){0,4}                      # Only do this 1 to 4 times, for it can't be more (parser hint to stop)
";

Regex.Matches(data, pattern, RegexOptions.IgnorePatternWhitespace) // Ignore is to allow commenting of the pattern only (not data processing)
    .OfType<Match>()
    .Select(mt => mt.Groups["Tokens"]
                    .Captures.OfType<Capture>()
                    .Select(cp => cp.Value))
    .ToList() // To do the foreach below
    .ForEach(tokens => Console.WriteLine(string.Join(" | ", tokens)));

/* Output
dbo | Product Sales for 1997
Northwind | My Schema | My view or table function
My view or table function
dbo | My View 1
*/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...