Я работаю над обзором всех таблиц и запросов во всех базах данных Access в данной папке, и моя цель — разделить код SQL, лежащий в основе запросов, на столбцы с помощью RegEx. Таким образом, я пытаюсь создать регулярное выражение, которое разбивает SQL по основным ключевым словам SQL и их наборам. См. код для считывания этих баз данных MS Access на странице Как получить код sql для запроса в MS Access, если атрибут «SQL» объекта запроса сохраняется как строка длиной всего 255 символов? - Суперпользователь.
Это дополнительный вопрос к Рабочее совпадение RegEx, которое начинается с первого из двух слов OR, вместо этого принимает нежелательное последнее слово OR, если я помещаю перед ним еще RegEx [дубликат] . Спасибо за полезные замечания этого пользователя и этого пользователя под этим вопросом.
Я получил:
(?>=SELECT\s+|,\s*)(.+)\s+AS\s+Error.?(?<=WHERE|HAVING)(.)
Или без всяких осмотров:
(?:=SELECT\s+|,\s*)(.+?)\s+AS\s+Error.?((?:WHERE|HAVING).)
в качестве необходимого RegEx для:
SELECT a, bc d AS Error FROM y WHERE 1=1 HAVING 1=1
разделить на две соответствующие группы:
bc d
в качестве кода, создающего столбец под названием «Ошибка». Это фиктивный код, не обращайте внимания на SQL.
Что-нибудь после одного из двух слов «ГДЕ» или «ИМЕЮ».
См. Regex101.
Протестировав все с языком и версией www.regex101.com по умолчанию, который PCRE2 (PHP >=7.3)
на момент написания статьи, он не работает в MS Access VBA, который выдает любой шаблон с обходом:
Microsoft Visual Basic — ошибка времени выполнения «5017»: ошибка, определяемая приложением или объектом.
С осмотрами:
regexPattern = "(?>=SELECT\s+|,\s*)(.+)\s+AS\s+Error.*?(?<=WHERE|HAVING)(.*)" '-> error 5017 pop up
regexPattern = "(?<=WHERE|HAVING)(.*)" '-> error 5017 pop up
regexPattern = "(?>=SELECT\s+|,\s*)(.+)\s+AS\s+Error.*" '-> error 5017 pop up
Без обходных путей кажется, что он работает в MS Access:
regexPattern = "(?:=SELECT\s+|,\s*)(.+?)\s+AS\s+Error.*?((?:WHERE|HAVING).*)" ' -> no error 5017, but no matches either
regexPattern = "((?:WHERE|HAVING).*)" '-> working
regexPattern = "(?:=SELECT\s+|,\s*)(.+?)\s+AS\s+Error" '-> working
Кажется, что MS Access VBA не может справиться с обходными путями. Может возникнуть что-то вроде двойного совпадения ранних и поздних регулярных выражений, с которым трудно справиться, если просмотры (просмотр вперед и просмотр назад) не разрешены в MS Access VBA (НЕПРАВИЛЬНО, см. конец ответа с просмотром вперед RegEx, который работает в MS Access VBA).
+++ РАЗУМ: ЭТО БЫЛО НЕПРАВИЛЬНО. С РАБОЧИМ РЕГИСТРАЦИОННЫМ ВЫРАЖНЕНИЕМ ДЛЯ MS ACCESS В ОТВЕТЕ НИЖЕ, Я ЗНАЮ ТЕПЕРЬ, ЧТО ПРОГЛАДУЮЩИЕ ЗАГОЛОВКИ МОЖНО ЧИТАТЬ С помощью MS ACCESS VBA +++ (я не знаю, почему это не сработало, но другое работает)
Мне нужно регулярное выражение, которое находит два совпадения, как показано выше, и останавливается перед order by
и работает в MS Access VBA:
Что такое RegEx:
Error
определение столбца (столбец, который всегда имеет вид 'my_error_text' AS Error
и без хвоста AS Error
,WHERE
/HAVING
, начиная с самого раннего из двух (это не обязательно, вы также можете вывести все наборы ключевых слов, каждый из которых будет в одной группе, только в моем проекте целью было получить те условия, которые фильтруют строки для ошибки)ORDER BY
? (это не обязательно)И вопрос не только для MS Access VBA. Я ищу код RegEx, который может разделить любой код SQL по его ключевым словам SQL, как в MS Access, так и в любом другом стиле SQL. Таким образом, приведенный выше список является лишь основной целью, но лучше было бы использовать «полный SQL RegEx».
Короче говоря, вопрос сводится к универсальному SQL RegEx: как разделить SQL-запрос с помощью RegEx?
vba
и ms-access
, поскольку этот вопрос полезен для любой задачи RegEx, направленной на разделение кода SQL или выборку из него.SELECT ... INTO ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY
)Что касается замечаний о том, что вам вообще не следует пробовать использовать RegEx с SQL, поскольку он подвержен всевозможным ошибкам, исходящим из диалектов, стилей и нетривиального кода, и поскольку он не работает хорошо: «Большое» в «Большом» RegEx for SQL» — это просто RegEx для тривиального кода SQL, такого как SELECT ... INTO ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY
. Любой нетривиальный SQL-код, скорее всего, не станет хорошей площадкой для полноценного RegEx, проверяющего все. Затем вам нужно разделить задачи RegEx. И, возможно, нетривиальный SQL вообще не является игровой площадкой для любого RegEx, поскольку на него никогда нельзя положиться, если в вашем коде могут быть выбросы SQL.
RegEx предназначен для менее чем 1000 таблиц и запросов, которые всегда распределены по базам данных MS Access в одном и том же стиле. Для такой маленькой выборки производительность роли не играет. Но если вы думаете о том, чтобы реализовать это в больших масштабах, например, для сотен тысяч SQL-запросов, не пытайтесь использовать RegEx.
У меня уже был этот вопрос много лет назад, но я так и не решился его задать: в сети нет RegEx для считывания тривиального SQL-запроса (до сих пор). Тем не менее, этот RegEx был бы запрошен не в 2024 году, а несколько десятилетий назад, если бы не было никаких оговорок.
Даже если ответ показывает, что вы можете сделать все с помощью одного RegEx, см. предпоследний скриншот для запуска в MS Access, который занимает около 15 секунд для 1000 объектов, часто будет проще, если вы попробуете другие способы. Например, если вы работаете в MS Access, попробуйте встроенные функции для разделения текста и/или напишите свою собственную функцию в VBA, которая даст вам возможность легко выполнять циклическое, двойное циклирование и разделение, лучше понимая что происходит и отлаживать.
С другой стороны, поскольку 15 секунд для 1000 объектов — это достаточно быстро, и поскольку это работает для тривиального кода SQL, и поскольку я ясно говорю вам здесь, что вам следует избегать RegEx для анализа SQL, я не понимаю, почему этот вопрос должен быть задан. закрыто. Есть опасение, что некоторые могут подумать, что RegEx — хороший путь. Тем не менее, просто опасаясь, что это несправедливо, поскольку я мог работать с RegEx, эта работа является достаточным доказательством того, что в некоторых небольших наборах данных с простым SQL RegEx действительно может помочь.
Суммируя:
Прочитав этот вопрос, не думайте, что разделение SQL на RegEx — хороший способ. SQL-анализ с регулярными выражениями подвержен ошибкам и не работает должным образом. Вы будете работать чище и быстрее с SQL или другими языками программирования, если вы:
SELECT t1.dummy1, t1.dummy2 AS Error, t1.dummy3 INTO testResult
FROM (test1 t1 INNER JOIN test2 t2 ON t1.dummy4 = t2.dummy4) INNER JOIN test3 t3 ON t2.dummy9 = t3.dummy9
WHERE t2.dummy6 = 'abc' AND t3.dummy10 <> 'def' AND t1.dummy11 = 'ghi' AND t2.dummy12 IS NULL
GROUP BY t1.dummy1
HAVING 1=1
ORDER BY 1;
SELECT
t1.dummy1,
t1.dummy2 AS Error,
t1.dummy3
INTO
testResult
FROM
(test1 t1
INNER JOIN test2 t2 ON t1.dummy4 = t2.dummy4)
INNER JOIN test3 t3 ON t2.dummy9 = t3.dummy9
WHERE
t2.dummy6 = 'abc'
AND t3.dummy10 <> 'def'
AND t1.dummy11 = 'ghi'
AND t2.dummy12 IS NULL
GROUP BY t1.dummy1
HAVING 1=1
ORDER BY 1;
@RyszardCzech Найти RegEx действительно кроличья нора, но я сомневаюсь, что вы здесь. Такого RegEx в сети до сих пор не было, а я помню, что он мне понадобился еще пять лет назад и удивлялся, почему никто до сих пор его не пробовал. Я отметил основные ответы ниже ++ Answer for ...
, чтобы было проще тем, кто просто хочет скопировать RegEx, а не читать все это. У меня это работает, достигнутые 1700 шагов не слишком много для RegEx в меньшем масштабе данных, так что здесь я с вами не согласен. SQL может проще разделить код SQL по умолчанию, но RegEx тоже может это сделать.
Вы никогда не получите регулярное выражение ни для одного из диалектов SQL, которое будет хорошо работать, за исключением, возможно, тривиальных запросов. Будущим читателям ни в коем случае не полагайтесь ни на какой ответ: вы будете сильно разочарованы.
@TT Я не говорил о диалектах, но думаю, что если это работает для TSQL/MS Access (а это работает), вы можете легко изменить его на любой другой диалект, поскольку в SQL есть некоторые правила, которые никогда не меняются. В этом разделе вопросов и ответов рассказывается о «стиле» SQL: разбивается ли SQL на разрывы строк по умолчанию, например, FROM
доходит до полного конца в одной строке (который я называю стилем SQL MS Access), или вы помещаете разрывы строк где угодно (это я называю случайным стилем SQL). Ниже приведен такой RegEx с доказательством того, что с его помощью считываются мои собственные базы данных Access (2-й последний снимок экрана), поэтому попробуйте.
@ТТ. Причем речь идет о тривиальных запросах, те, что я получаю из баз данных, — это просто тривиальные SELECT
запросы без вложенного кода, без CTE:s и тому подобного. Просто SELECT (INTO) FROM WHERE GROUP BY HAVING ORDER BY
, это объем этого вопроса, см. тестовый SQL в конце вопроса. Вот почему вы, возможно, правы, говоря, что RegEx плох для нетривиального кода SQL, но это выходит за рамки данного вопроса.
@ТТ. Я включил в вопрос новый заголовок о сфере применения. Хороший момент в отношении выступления, которое я изначально наблюдал.
Два трюка:
.*
, и нет необходимости проверять какие-либо случайные разрывы строк, поскольку MS Access всегда будет придерживаться разрывов строк по умолчанию.Вот RegEx, в котором реализованы эти два трюка (но имейте в виду, он завершится неудачей, как только будет пропущено одно ключевое слово):
ЭТО НЕПРАВИЛЬНОЕ РЕГИСТРА (работает, только если выбраны все ключевые слова):
SELECT (.*) (?:INTO (.*)).*\sFROM (.*)(?:\sWHERE (.*)).*(?:\sHAVING (.*)).*(?:\sORDER BY (.*)).*
Благодаря этому вы можете размещать множество команд подряд, всегда зная, когда остановиться, и вам не понадобится никакой предварительный просмотр. Вы всегда можете сделать что-то ленивым, сделав это группой без захвата и написав позади нее .*
(или то, что вы хотите съесть). Я узнал об этом из полезных замечаний ниже Рабочее совпадение RegEx, которое начинается с первого из двух слов OR, вместо этого берет нежелательное последнее слово OR, если я помещаю перед ним больше RegEx [дублировать].
https://regex101.com/r/3bItXm/1
Таким образом, если я откажусь от объединения WHERE
и HAVING
в одну группу, мне будет гораздо проще получить их оба, а затем я также смогу разделить ORDER BY
из SQL. Если я все еще хочу, чтобы некоторые из них были объединены в выходные данные, я могу сделать это позже, объединив выходные данные двух групп в коде VBA.
Это RegEx, который также считывает столбец «Ошибка»:
ЭТО НЕПРАВИЛЬНОЕ РЕГИСТРА (работает, только если выбраны все ключевые слова):
SELECT .*(?:, (.*) AS Error).* (?:INTO (.*)).*\sFROM (.*)(?:\sWHERE (.*)).*(?:\sHAVING (.*)).*(?:\sORDER BY (.*)).*
https://regex101.com/r/b7YaKq/1
Однако, как только одно из ключевых слов не найдено, весь RegEx терпит неудачу. Ленивые группы без захвата, похоже, не работают должным образом.
ЭТО НЕПРАВИЛЬНОЕ РЕГИСТРА (работает, только если выбраны все ключевые слова):
https://regex101.com/r/Jf3eth/1
Если не выбрано хотя бы одно ключевое слово, это не удастся:
https://regex101.com/r/dEFHKV/1
Я пытался сделать все группы необязательными с помощью ?
, но ничего не получилось: можно было сделать это только с самой последней ORDER BY
, но этого недостаточно.
WHERE
до конца до ORDER BY
» (работает)Это самый быстрый RegEx, который вы можете получить для решения поставленной задачи. Ему нужно всего 400 шагов, но он не опускается ORDER BY
в конце, так что последний блок WHERE
/HAVING
распределяется по всем строкам до ORDER BY
.
++ Ответ на определение столбца и блока WHERE/HAVING... (с ORDER BY в конце) в SQL-коде в стиле MS Access SQL за 400 шагов (без обходных путей) ++
^\s*(?:(?:=SELECT\s+|.*,\s*)([^,]+?)\s+AS\s+Error[\s\S]*?)?(?:(?:WHERE|HAVING)\s*([\s\S]*)?)$
https://regex101.com/r/mLQRVu/1
Имейте в виду, что простое размещение еще одной группы без захвата (?:ORDER.*)
в конце не избавит от довольно нежелательной ORDER BY
(см. цели вопроса), поскольку это явно не сработает, если ORDER BY
отсутствует:
ЭТО НЕПРАВИЛЬНОЕ РЕГИСТРА (работает только при нажатии ORDER BY
):
(?:(?:=SELECT\s+|,\s*)([^,]+?)\s+AS\s+Error[\s\S]*?)?(?:((?:WHERE|HAVING)[\s\S]*)?)(?:ORDER.*)
Без ключевого слова ORDER BY
ничего не будет найдено, поскольку оно не является необязательным:
И учтите, что добавление ?
в конце в (?:ORDER.*)?
также не работает, поскольку [\s\S]*
в предыдущем блоке уже съест его, а ORDER BY
будет есть, пока не дойдет до конца:
ЭТО РЕГОВОРЕНИЕ С (?:ORDER.*)?
НЕ НУЖНО (всегда съедается до того, как оно будет достигнуто):
(?:(?:=SELECT\s+|,\s*)([^,]+?)\s+AS\s+Error[\s\S]*?)?(?:((?:WHERE|HAVING)[\s\S]*)?)(?:ORDER.*)?
INTO
, FROM
и одним блоком: «WHERE
до конца до ORDER BY
» (работает)В итоге я получил это регулярное выражение, чтобы получить определение выбранного столбца, «в», «откуда» и «где/иметь/упорядочить по». Создать этот код непросто, так как обходные пути не разрешены (ЗДЕСЬ НЕПРАВИЛЬНОЕ ПРЕДПОЛОЖЕНИЕ, см. рабочий просмотр вперед-RegEx в конце). Требуется 700 шагов.
++ Ответ на определение столбца INTO, FROM и блока WHERE/HAVING... (с ORDER BY в конце) в SQL-коде в стиле MS Access SQL за 700 шагов (без обходных путей) ++
^(?:(?:\s*?SELECT\s+|,\s*)[\s\S]*?\s?([^,]+?)\s+AS\s+Error[\s\S]*?)?[\s\S]*?(?:(?:\s+INTO\s+([\S]+)))?(?:(?:\s+FROM\s+([\S+].*)))?(?:\s+((?:WHERE|HAVING)[\s\S]*))?$
Хотя я не знал, как избежать ORDER BY
, но я могу смириться с результатом. Кроме того, попадание полного набора «из» - это удача, это зависит от того, чтобы все было в одной строке, но, похоже, в Access это значение по умолчанию. .*
остается внутри строки, только [\s\S]*
(или короче: [^*]*
) будет съедать разрывы строк. Что касается WHERE
/HAVING
, я не могу избавиться от ORDER BY
, поскольку это будет работать, только если я проверю WHERE
и HAVING
оба по отдельности, а не как набор. Теперь я не могу просто взять .*
, так как это приведет к удалению HAVING
:
И в запросах часто нет одного или нескольких символов WHERE
, HAVING
или ORDER BY
, поэтому я не могу просто шаг за шагом искать эти разрывы строк.
Короче говоря, ORDER BY
необходимо брать вместе с [^*]*
, иначе вы потеряете HAVING
, если есть WHERE
и вы получите код с помощью .*
.
?>=...
, на RegEx без обходов, то есть группу без захвата, за которой следовал .*
, чтобы сделать ее ленивой с (?:...).*
..*
, который остается только в строке, но это будет работать только в том случае, если у вас нет разрывов строк внутри набора и разрыва строки после него, например, если FROM ...
не разрезается на разрывы строк, и хорошая новость в том, что MS Access помещает разрывы строк только между основными командами, чтобы, например, MS Access не разрезал длинный набор FROM ... ON ... = ...
более чем на одну строку.Этот RegEx выполняет 459 шагов.
++ Ответ на определение столбца INTO, FROM, WHERE, HAVING, ORDER BY в SQL-коде в стиле MS Access SQL за 459 шагов (без обходных путей) ++
^(?:(?:\s*?SELECT\s+|,\s*)[\s\S]*?\s?([^,]+?)\s+AS\s+Error[\s\S]*?)?[\s\S]*?(?:(?:\s+INTO\s+([\S]+)))?(?:(?:\s+FROM\s+(.*)))?(?:(?:\s+WHERE\s+(.*)))?(?:(?:\s+GROUP\s+BY\s+(.*)))?(?:(?:\s+HAVING\s+(.*)))?(?:(?:\s+ORDER BY\s+(.*)))?$
https://regex101.com/r/YPtvxA/1
И это также работает, если ключевые слова отсутствуют:
Или, если вам нужно все SELECT
вместо определения только одного столбца, но тогда вы не можете поймать INTO
из блока SELECT
, поскольку INTO
находится в той же строке:
++ Ответ на SELECT (+ INTO), FROM, WHERE, HAVING, GROUP BY, ORDER BY в SQL-коде в стиле MS Access SQL за 100 шагов (без обходных путей) ++
^(?:(?:\s*SELECT\s+(.*)))?[\s\S]*?(?:(?:\s+FROM\s+(.*)))?(?:(?:\s+WHERE\s+(.*)))?(?:(?:\s+GROUP\s+BY\s+(.*)))?(?:(?:\s+HAVING\s+(.*)))?(?:(?:\s+ORDER BY\s+(.*)))?$
https://regex101.com/r/t2K2tH/1
Только для того, чтобы сделать его читабельным (без настоящего RegEx):
^
(?:(?:\s*SELECT\s+(.*)))?[\s\S]*?
(?:(?:\s+FROM\s+(.*)))?
(?:(?:\s+WHERE\s+(.*)))?
(?:(?:\s+GROUP\s+BY\s+(.*)))?
(?:(?:\s+HAVING\s+(.*)))?
(?:(?:\s+ORDER BY\s+(.*)))?
$
Это работает, если ключевые слова отсутствуют. Главный трюк для этого и нескольких шагов — это двойные знаки вопроса в ?[\s\S]*?
после блока SELECT
— не спрашивайте меня, почему...:
Он не работает со случайным стилем SQL (случайные разрывы строк), но это не было целью данной главы:
Имейте в виду, что для того, чтобы поймать INTO
, потребуется гораздо больше шагов. Это невозможно сделать просто так:
ЭТО РЕГИСТРА С НЕНУЖНЫМ КОДОМ (оно не ловит INTO
, но все равно его записывает):
^(?:(?:\s*SELECT\s+(.*)))?[\s\S]*?(?:(?:\s+INTO\s+([\S]+)))?(?:(?:\s+FROM\s+(.*)))?(?:(?:\s+WHERE\s+(.*)))?(?:(?:\s+GROUP\s+BY\s+(.*)))?(?:(?:\s+HAVING\s+(.*)))?(?:(?:\s+ORDER BY\s+(.*)))?$
Таким образом, вместо ?
ему нужен .*
в качестве ленивых привязок, а также мне нужны заполнители для пробела, который появляется, если одно из ключевых слов в строке не известно или не найдено и его необходимо перепрыгнуть, см., например, [\s\S]*\s+ORDER
, где [\s\S]*
может также можно писать кратко как [^*]*
. Это приводит к 45 000 шагов, чтобы поймать INTO
:
++ Ответ на полный код SQL (SELECT, INTO, FROM, WHERE, HAVING, GROUP BY, ORDER BY) в стиле MS Access SQL за 47 000 шагов (без обходных путей) ++
^(?:(?:\s*SELECT\s+(.*))).*(?:(?:[\s\S]*\s+INTO\s+([\S]+))).*(?:(?:[\s\S]*\s+FROM\s+(.*))).*(?:(?:[\s\S]*\s+WHERE\s+(.*)))?.*(?:(?:[\s\S]*\s+GROUP\s+BY\s+(.*)))?.*(?:(?:[\s\S]*\s+HAVING\s+(.*)))?.*(?:(?:[\s\S]*\s+ORDER\s+BY\s+(.*)))?.*$
https://regex101.com/r/Gpj0Wa/1
Только для того, чтобы сделать его читабельным (без настоящего RegEx):
^
(?:(?:\s*SELECT\s+(.*))).*
(?:(?:[\s\S]*\s+INTO\s+([\S]+))).*
(?:(?:[\s\S]*\s+FROM\s+(.*))).*
(?:(?:[\s\S]*\s+WHERE\s+(.*)))?.*
(?:(?:[\s\S]*\s+GROUP\s+BY\s+(.*)))?.*
(?:(?:[\s\S]*\s+HAVING\s+(.*)))?.*
(?:(?:[\s\S]*\s+ORDER\s+BY\s+(.*)))?.*
$
Это работает с отсутствующими ключевыми словами:
И это не работает со случайным стилем SQL, но это не было целью этой главы:
Теперь вы можете самостоятельно определить определение столбца «Ошибка», если хотите разделить весь SQL (с установленным SELECT
) и определение этого выбранного столбца, как я это сделал в конце. Получение определения столбца занимает 168 шагов.
^(?:(?:\s*SELECT\s+|,\s*)[\s\S]*?\s?([^,]+?)\s+AS\s+Error[\s\S]*?)?[\s\S]*$
Или короче, и за 160 шагов:
++ Ответ на определение столбца «Ошибка» SQL-кода в MS Access или случайного стиля SQL за 160 шагов (без обходных путей) ++
(?:SELECT\s+|,\s*)[\s\S]*?\s?([^,]+?)\s+AS\s+Error
И это также будет работать в любом SQL произвольного стиля с разрывами строк повсюду между определением столбца и именем столбца, что означает "abc" AS Error
всегда не в одной строке, занимая 179 шагов:
https://regex101.com/r/fhe98K/1
Я думаю, что вы не можете поместить это все в одно и то же регулярное выражение, поскольку группа соответствия SELECT ...
в «большом регулярном выражении SQL» выше уже использует символы, которые здесь необходимы. Но проверка кода SQL во второй раз не представляет большого труда.
Ссылки, для начала:
Регулярное выражение с опережением просмотра (?>=
, так же, как ?=
) вместо ленивых привязок ((?:...).*
или (?:...)[^*]*
) намного длиннее, но его легче понять: вы просто проверяете наличие следующего ключевого слова, пока не дойдете до конца кода SQL. Если вы найдете другое ключевое слово, вы остановитесь, и просмотр вперед не съест найденные символы, а оставит их для следующей группы в качестве начального ключевого слова.
Их легче понять не только человеку, но и машине: просмотр вперед требует гораздо меньше шагов, чем ленивые привязки.
Этому регулярному выражению требуется 2900 шагов:
++ Ответ на полный код SQL в случайном стиле SQL за 2900 шагов (с обходами) ++
^(?=\s*SELECT\s+([\s\S]*?)(?=\s+(?:INTO|FROM|WHERE|GROUP\s+BY|HAVING|ORDER\s+BY)\s))(?=(?:[\s\S]*?\s+INTO\s+([\S]+)\s*)?)(?=(?:[\s\S]*?\s+FROM\s+([\s\S]*?)(?=\s+(?:WHERE|GROUP\s+BY|HAVING|ORDER\s+BY)\s)))(?=(?:[\s\S]*?\s+WHERE\s+([\s\S]*?)(?=\s+(?:GROUP\s+BY|HAVING|ORDER\s+BY)\s)))(?=(?:[\s\S]*?\s+GROUP\s+BY\s+([\s\S]*?)(?=\s+(?:HAVING|ORDER\s+BY)\s))?)(?=(?:[\s\S]*?\s+HAVING\s+([\s\S]*?)(?=\s+ORDER\s+BY\s))?)(?=(?:[\s\S]*?\s+ORDER\s+BY\s+([\s\S]*?)(?=\s*$))).*$
https://regex101.com/r/LCI3OB/2
Здесь он находится в читаемых блоках ключевых слов. Однострочник для INTO
не является ошибкой, он должен содержать только имя следующей таблицы.
Только для того, чтобы сделать его читабельным (без настоящего RegEx):
^
(?=\s*SELECT\s+([\s\S]*?)
(?=\s+(?:INTO|FROM|WHERE|GROUP\s+BY|HAVING|ORDER\s+BY)\s))
(?=(?:[\s\S]*?\s+INTO\s+([\S]+)\s*)?)
(?=(?:[\s\S]*?\s+FROM\s+([\s\S]*?)
(?=\s+(?:WHERE|GROUP\s+BY|HAVING|ORDER\s+BY)\s)))
(?=(?:[\s\S]*?\s+WHERE\s+([\s\S]*?)
(?=\s+(?:GROUP\s+BY|HAVING|ORDER\s+BY)\s)))
(?=(?:[\s\S]*?\s+GROUP\s+BY\s+([\s\S]*?)
(?=\s+(?:HAVING|ORDER\s+BY)\s))?)
(?=(?:[\s\S]*?\s+HAVING\s+([\s\S]*?)
(?=\s+ORDER\s+BY\s))?)
(?=(?:[\s\S]*?\s+ORDER\s+BY\s+([\s\S]*?)
(?=\s*$))).*
$
Это не должно работать, поскольку в нем есть обходные пути, см. вопрос (УМЬ: Я ОШИБАЛСЯ, ПРЕДПОЛАГАЯ, ЧТО ДОСТУП НЕ МОЖЕТ СВЯЗАТЬСЯ С ОБЗОРАМИ). Как ни странно, этот RegEx выдает другую ошибку, чем ошибка в вопросе, возникшая при анализе SQL с помощью regex.Execute(obj_SQL)
:
Microsoft Visual Basic — ошибка времени выполнения «5017»: ошибка, определяемая приложением или объектом.
Теперь ошибка появляется на одну строку после regex.Execute(obj_SQL)
:
Ошибка выполнения/времени «5»: неверный вызов процедуры или аргумент.
Хотя RegEx работает на веб-сайте Regex101, он вообще не может найти ни одну группу в MS Access. Ошибка возникает всякий раз, когда вы звоните matches(0).SubMatches(0)
или любой другой номер группы, заканчивающийся на matches(0).SubMatches(6)
.
Это означает, что мы не можем запустить этот RegEx в MS Access и, как ни странно, ошибка изменилась.
Имейте в виду, что это касается только SQL, который выдает MS Access, или чего-либо еще, что соответствует такому SQL по умолчанию.
В этом предварительном регулярном выражении есть еще .*
, который не может передать перенос строки. Следующему регулярному выражению требуется 3000 шагов:
ЭТО НЕПРАВИЛЬНОЕ РЕГИСТРАЦИОННОЕ ВЫРАЖЕНИЕ:
^(?=\s*SELECT\s+(.*?)(?=\s+INTO|\s+FROM|$))(?=(?:.*?\s+INTO\s+([\S]+)\s+)?)(?=(?:.*?\s+FROM\s+(.*?)(?=\s+WHERE|\s+GROUP\s+BY|\s+HAVING|\s+ORDER\s+BY|$)))(?=(?:[\s\S]*?\s+WHERE\s+(.*?)(?=\s+GROUP\s+BY|\s+HAVING|\s+ORDER\s+BY|$))?)(?=(?:[\s\S]*?\s+GROUP\s+BY\s+(.*?)(?=\s+HAVING|\s+ORDER\s+BY|$))?)(?=(?:[\s\S]*?\s+HAVING\s+(.*?)(?=\s+ORDER\s+BY|$))?)(?=(?:[\s\S]*?\s+ORDER\s+BY\s+(.*?)(?=\s*$))?).*$
https://regex101.com/r/hMBtdd/2
Тем не менее, это неправильный RegEx. Заполняет таблицу только в столбцах «Ошибка», «Выбрать», «В». Остальное остается пустым. Из вывода для трех рабочих «Ошибка», «Выбрать», «В» мы видим, что MS Access VBA может обрабатывать обходные пути, и это хорошая новость.
Тогда, возможно, просто совершенно неясно, какой вкус ему нужен. Я проверил их все, и только языки Golang и Rust не работают, да и вообще не работают, ничего не найдено:
Остальные вкусы работают. Похоже, это не объясняет, почему MS Access может не понимать RegEx.
Оказалось, что матч («Матч 1», но матч все равно один) остановился до FROM
. Без совпадения в фоновом режиме вы не сможете иметь соответствующую группу на переднем плане, даже если Regex101 найдет группу. Создание «Сопоставления 1» при условии, что код снова заставит его работать, и он выполняется всего за 1700 шагов:
++ Ответ на полный код SQL в стиле MS Access SQL за 1700 шагов (с обходами) ++
^(?:SELECT\s+([\s\S]+?)(?=\s+INTO\s+|\s+FROM|$))(?:.*?\s+INTO\s+([\S]+)\s*)?(?:\s+FROM\s+)([\s\S]+?)(?=\s+WHERE\s+|\s+GROUP\sBY\s+|\s+HAVING\s+|\s+ORDER\sBY|$)(?:.*?\s+WHERE\s+([\s\S]+?)(?=\s+GROUP\sBY\s+|\s+HAVING\s+|\s+ORDER\sBY|$))?(?:.*?\s+GROUP\sBY\s+([\s\S]+?)(?=\s+HAVING\s+|\s+ORDER\sBY|$))?(?:.*?\s+HAVING\s+([\s\S]+?)(?=\s+ORDER\sBY\s+|$))?(?:.*?\s+ORDER\sBY\s+([\s\S]+?)(?=\s*$))?$
https://regex101.com/r/Pn04Gp/1
Здесь вы видите один и тот же код с переносом строки для каждого блока ключевых слов. Имейте в виду, что INTO
не может найти более одной целевой таблицы и, следовательно, не нуждается в предварительном просмотре, чтобы проверить, где будет следующее ключевое слово, он просто съедает имя следующей таблицы.
Только для того, чтобы сделать его читабельным (без настоящего RegEx):
^
(?:SELECT\s+([\s\S]+?)
(?=\s+INTO\s+|\s+FROM|$))
(?:.*?\s+INTO\s+([\S]+)\s*)?
(?:\s+FROM\s+)([\s\S]+?)
(?=\s+WHERE\s+|\s+GROUP\sBY\s+|\s+HAVING\s+|\s+ORDER\sBY|$)
(?:.*?\s+WHERE\s+([\s\S]+?)
(?=\s+GROUP\sBY\s+|\s+HAVING\s+|\s+ORDER\sBY|$))?
(?:.*?\s+GROUP\sBY\s+([\s\S]+?)
(?=\s+HAVING\s+|\s+ORDER\sBY|$))?
(?:.*?\s+HAVING\s+([\s\S]+?)
(?=\s+ORDER\sBY\s+|$))?
(?:.*?\s+ORDER\sBY\s+([\s\S]+?)
(?=\s*$))?
$
Таким образом, это доказательство того, что просмотры работают и в MS Access VBA, и что вопрос был неправильным, когда предполагалось, что просмотры не могут быть прочитаны.
Выходные данные MS Access:
Имейте в виду, что тот же RegEx не будет работать для других стилей вывода SQL:
Чтобы это работало, выше уже есть другой работающий RegEx. Вы не можете запустить это в MS Access VBA, но это работает.
НИКОГДА не анализируйте SQL с помощью одного регулярного выражения. То, что вы здесь написали, может заставить других подумать, что это нормально, хотя это опасная кроличья нора, которая уходит слишком глубоко.