19.9.25

Новое в SQL Server 2025: REGEXP_INSTR и REGEXP_COUNT

Автор: Louis Davidson, And the rest – REGEXP_INSTR, and REGEXP_COUNT

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

В этой статье мы рассмотрим:

  • REGEXP_INSTR — Возвращает начальную или конечную позицию соответствующей подстроки в зависимости от значения аргумента return_option.
  • REGEXP_COUNT — Подсчитывает количество совпадений шаблона регулярного выражения в строке.

REGEXP_INSTR

В SQL Server нет функции INSTR, хотя PATINDEX служит достаточно близким аналогом для сравнения. PATINDEX принимает два параметра — входную строку и LIKE-выражение, позволяя найти первый символ первого вхождения этого шаблона. Например:

SELECT PATINDEX('%3%','1234567890');

Это возвращает 3. Цифра 3 явно находится в позиции 3, но с символами '%', окружающими её, может показаться, что должно быть 1. Но точно так же, как мы ищем шаблон с помощью регулярных выражений с открытым шаблоном, PATINDEX также использует "любое количество любых символов" в шаблоне поиска вместе с конкретным строковым значением, которое вы ищете, если хотите (поиск шаблона '%' вернёт 1 даже для пустой строки).

REGEXP_INSTR имеет эти (уже знакомые по серии) параметры, за исключением одного:

REGEXP_INSTR
(
string_expression,
pattern_expression
[, start [, occurrence [, return_option [, flags [, group ] ] ] ] ]
)

Параметр return_option — я опишу ниже.

Простейшая форма:

В простейшей форме вы просто передаёте строковое значение и шаблон для поиска. Этот шаблон соответствует цифре 3 (плюс любые символы до и после).

SELECT REGEXP_INSTR('1234567890','3');

Это возвращает:

-----------
3

Поскольку цифра 3 находится в третьей позиции.

Добавление параметров start и occurrence

Параметры start и occurrence работают точно так же, как в функции REGEXP_SUBSTR. Вы можете использовать один для поиска местоположения значения, а другой для поиска фактического значения с теми же начальными 4 параметрами.

Например, используя строку чисел из статьи о REGEXP_SUBSTR, я найду шаблон для первого, второго и третьего вхождений.

SELECT REGEXP_INSTR('1234567890','\d{3}',1,1) AS Loc_1,
       REGEXP_SUBSTR('1234567890','\d{3}',1,1) AS Value_1,
       REGEXP_INSTR('1234567890','\d{3}',1,2) AS Loc_2,
       REGEXP_SUBSTR('1234567890','\d{3}',1,2) AS Value_2,
       REGEXP_INSTR('1234567890','\d{3}',1,3) AS Loc_3,
       REGEXP_SUBSTR('1234567890','\d{3}',1,3) AS Value_3

Как видите, это позиции 1, 4 и 7, а также найденные значения:

Loc_1   Value_1  Loc_2   Value_2    Loc_3   Value_3
------- -------- ------- ---------- ------- ----------
1       123      4       456        7       789

Параметр return_option

Одно главное отличие REGEXP_INSTR от других рассмотренных нами функций — это параметр return_option. Он показывает позицию сразу после окончания шаблона. Это немного сбивает с толку (и числовой параметр не очень в этом помогает), но с этим значением вы можете найти начало и конец (и, вычтя 1 из значения), можете найти местоположение начала и конца совпадения с вашим шаблоном.

Возможные значения параметра return_option:

0 (по умолчанию) — вернуть начальную позицию значения
1 — вернуть первую позицию после значения

В следующем фрагменте кода я добавил значение return_option 0 или 1 для начала и конца каждой позиции:

SELECT REGEXP_INSTR('1234567890','\d{3}',1,1,0) AS Start_1,
       REGEXP_INSTR('1234567890','\d{3}',1,1,1) AS NextPos_1,
       REGEXP_SUBSTR('1234567890','\d{3}',1,1) AS Value_1,
       REGEXP_INSTR('1234567890','\d{3}',1,2,0) AS Start_2,
       REGEXP_INSTR('1234567890','\d{3}',1,2,1) AS NextPos_2,
       REGEXP_SUBSTR('1234567890','\d{3}',1,2) AS Value_2;

Это возвращает:

Start_1  NextPos_1   Value_1  Start_2   NextPos_2   Value_2
-------- ----------- -------- --------- ----------- --------
1        4           123      4         7           456 

Здесь я не совсем уверен в сценарии использования  потому что в основном мне нужны позиции значений для использования с вызовами функций SUBSTRING/RIGHT/LEFT, но со всей мощью семейства функций REGEXP_%, большая часть работы со строками делается за нас.

Параметр group

Пропуская параметр flag, который работает так же, как в предыдущих функциях, есть параметр group. Этот параметр работает очень похоже на то, как это было в функции REGEXP_SUBST (и, как я покажу, это даст вам местоположение группы, которую вы могли получить с помощью вызова REGEXP_SUBSTR).

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

SELECT REGEXP_INSTR(
                    --Значение для разбора:
                    'abc1234567890987654321',
                    --Шаблон регулярного выражения:
                    '(\d{1})(\d{2})',
                    --Начальная позиция:
                    1,
                    --Вхождение:
                    2,
                    --Опция возврата:
                    0, --(означает вернуть начало)
                    --Флаги:
                    '',
                    --Группа:
                    2
                    ) AS REGEXP_INSTR_2

Это возвращает:

REGEXP_INSTR_2
--------------
8

Рассматривая значение:

Позиция: 1234567890123456789012
Значение: abc1234567890987654321

Вы можете видеть, что первая цифра 4 находится в позиции 7 (и что первый символ находится во второй группе из 3 цифр). Первая группа начинается в позиции 7 и имеет длину один символ. Поэтому вторая группа появляется в 8-й позиции. Для более подробного рассмотрения:

SELECT REGEXP_SUBSTR('abc1234567890987654321',
              '(\d{1})(\d{2})',1,2) as REGEXP_SUBSTR,
REGEXP_SUBSTR('abc1234567890987654321',
              '(\d{1})(\d{2})',1,2,'',1) as REGEXP_SUBSTR_1,
REGEXP_SUBSTR('abc1234567890987654321',
              '(\d{1})(\d{2})',1,2,'',2) as REGEXP_SUBSTR_2
SELECT REGEXP_INSTR('abc1234567890987654321',
              '(\d{1})(\d{2})',1,2) as REGEXP_INSTR,
REGEXP_INSTR('abc1234567890987654321',
              '(\d{1})(\d{2})',1,2,0,'',1) as REGEXP_INSTR_1,
REGEXP_INSTR('abc1234567890987654321',
              '(\d{1})(\d{2})',1,2,0,'',2) as REGEXP_INSTR_2

Это выводит:

REGEXP_SUBSTR  REGEXP_SUBSTR_1  REGEXP_SUBSTR_2
-------------- ---------------- ---------------
456            4                56
REGEXP_INSTR   REGEXP_INSTR_1   REGEXP_INSTR_2
-------------- ---------------- ---------------
7              7                8

Как видите, это очень похоже на рассмотренный ранее пример, где вы можете видеть строку и группы в вызовах REGEXP_SUBSTR и их местоположения в вызовах REGEXP_INSTR.

REGEXP_COUNT

Назначение этой функции — подсчитать количество совпадений, которые вы найдёте для шаблона в строке.

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

Синтаксис:

REGEXP_COUNT (
         string_expression,
         pattern_expression [ , start [ , flags ] ]
)

Эта функция имеет только самые базовые параметры с дополнительным параметром start для указания начальной позиции обработки и flags, когда они нужны. Для примера я использую ту же строку и шаблон, с которыми мы работали:

SELECT REGEXP_COUNT('abc1234567890987654321',
                      '(\d{1})(\d{2})') as REGEXP_COUNT;

Это возвращает:

REGEXP_COUNT
------------
6

В этом контексте это точно то же самое, что и \d{3}, как видите здесь:

SELECT REGEXP_COUNT('abc1234567890987654321',
                         '\d{3}') as REGEXP_COUNT;

Мы можем увидеть это двумя способами: либо просто подсчитав их:

111222333444555666
abc1234567890987654321

Или используя REGEXP_MATCHES и видя, сколько строк она выводит:

SELECT match_id, start_position, end_position, match_value
FROM   REGEXP_MATCHES('abc1234567890987654321','\d{3}') AS MATCHES;

Вы можете видеть символы в различных совпадениях:

match_id   start_position end_position match_value
---------- -------------- ------------ ------------
1          4              6            123
2          7              9            456
3          10             12           789
4          13             15           098
5          16             18           765
6          19             21           432

Что даёт 6 строк, по 1 для каждого совпадения, что вы видели в примере с REGEXP_COUNT.

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


Комментариев нет:

Отправить комментарий