SAP HANA SQL SUBSTR_REGEXPR Агрегация совпадений - PullRequest
0 голосов
/ 09 февраля 2019

Я использую HANA и пытаюсь создать новый столбец на основе следующего:

  Regex Example 1: SUBSTR_REGEXPR('([PpSs][Tt][Ss]?\w?\d{2,6})' in "TEXT") as "Location"

Как получить этот результат, чтобы он возвращал все результаты, а не только первый?Повторяется ли строчная агг этого выражения?В каждом текстовом поле (в каждой строке) может быть не более 6 совпадений.

Regex Пример 1 Токовый выход:

Row                    Text                           Location(new column)
 1        msdfmsfmdf PT2222, ST 43434 asdasdas              PT2222

Regex Пример 1 Желаемый вывод:

Row                    Text                           Location(new column)
 1        msdfmsfmdf PT2222, ST 43434 asdasdas              PT2222, ST43434

У меня также есть различные форматы, поэтому мне нужно иметь возможность использовать несколько вариантов этого регулярного выражения, чтобы иметь возможность захватывать все совпадения и помещать их в новый столбец «Расположение» в качестве агрегированного разделителя.Возможно ли это?

В одном из других вариантов мне нужно было бы извлечь числа из этой серии:

   "Locations 1, 2, 35 & 5 lkfaskjdlsaf .282 lkfdsklfjlkdsj 002"

Пока у меня есть:

  Regex Example 2: "Locations (\d{1,2}.?){1,5}"

но я знаю, что это не работает.Когда я удаляю «Локации», он берет цифры, но также забирает .282 и 002, которые мне не нужны.

Regex Пример 2 Токовый вывод:

Row                    Text                           Location(new column)
 1        msdfmsfmdf Locations 3,5,7 & 9" asdasdas         Locations 3

Пример Regex2 Желаемый результат:

Row                    Text                           Location(new column)
 1        msdfmsfmdf Locations 3,5,7 & 9" asdasdas           3,5,7,9 

Иногда «Местоположение» в текстовом поле имеет формат, который потребует регулярное выражение примера 1, а иногда - формат, требующий регулярного выражения примера 2s, поэтому мне нужно иметьпоиск в регулярном выражении для обоих возможных форматов.

 Example 3 Regex in Select Statement: 
     Select "Primary Key",
     "Text", 
     STRING_AGG(SUBSTR_REGEXPR('([PpSs][Tt][Ss]?\w?\d{2,6})' OR '(\d{1,2}.?){1,5})' in "Text" ),',') as "Location"
     FROM Table

Необходимо захватить оба формата местоположения примера 1 и 2, используя какое-либо условие ИЛИ в столбце создания SQL

 Regex Example 3 Current Output:

                   Not working, no output

Regex Пример 3 ЖелаемыйВывод:

Row                    Text                           Location(new column)
 1        msdfmsfmdf Locations 3,5,7 & 9" asdasdas           3,5,7,9
 2        msdfmsfmdf PT2222, ST 43434 asdasdas            PT2222, ST43434

Другие инструменты, к которым у меня есть доступ, это SAS и python.Любые альтернативные рекомендации для упрощения процесса приветствуются.Я уже пробовал в Таблице, но та же проблема с возвращением только первого матча.Их объединение делает вычисления очень медленными и очень длинными.

Пожалуйста, помогите мне разобраться в этом.Любая помощь очень ценится.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Для значений одной входной строки можно использовать следующий скрипт.Использование SubStr_RegExpr с Series_Generate_Integer для разделения строки с использованием SQLScript в HANA может быть наглядным для понимания использования функции series_generate

declare pString nvarchar(5000);
pString := 'msdfmsfmdf PT2222, ST 43434 asdasdas';

select
 STRING_AGG(SUBSTR_REGEXPR( '([PpSs][Tt][Ss]?\w?\d{2,6})' IN Replace(pString,' ','') OCCURRENCE NT.Element_Number GROUP 1),',') as "Location"
from
 DUMMY as SplitString,
 SERIES_GENERATE_INTEGER(1, 0, 10 ) as NT; 

Вывод будет возвращен как PT2222, ST43434

0 голосов
/ 12 февраля 2019

Спасибо за добавление необходимых примеров требований.Это значительно облегчает решение проблемы.

В этом случае вам необходимо сопоставить несколько строк с несколькими шаблонами и применить несколько операций форматирования на выходе.

Этого нельзя сделать в регулярном выражении single в SAP HANA.

По сути, SAP HANA SQL допускает два вида операций регулярного выражения:

  • Сопоставление с шаблоном и возврат один вхождение
  • Сравнение с шаблоном и замена одного или ВСЕХ вхождений этого совпадения

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

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

Для этого можно создать скалярную пользовательскую функцию .как это:

drop function extract_locators;

create function extract_locators(IN input_text NVARCHAR(1000))
returns location_text NVARCHAR(1000)
as 
begin
declare matchers  NVARCHAR(100) ARRAY;
declare part_res NVARCHAR(100) := '';
declare full_res NVARCHAR (2000) := '';
declare occn integer;
declare curr_matcher integer;

-- setting up matchers
    matchers[1] :=  '(PT\s*[[:digit:]]+)|(ST\s*[[:digit:]]+)';  -- matches PTxxxx, pt xxxx , St ... , STxxxx
    matchers[2] := '(?>\s)[1-9][0-9]*'; -- matches 21, 1, 23, 34

    curr_matcher :=0;
    -- loop over all matchers
    while (:curr_matcher < cardinality(:matchers)) do
        curr_matcher := :curr_matcher + 1;
        -- loop over  all occurrences

        occn := 1;
        part_res := '';
        while (:part_res IS NOT NULL) do
            part_res := SUBSTR_REGEXPR(:matchers[:curr_matcher]  
                                        FLAG 'i' 
                                        IN :input_text  
                                        OCCURRENCE :occn);
            if (:part_res IS NOT NULL) then
                occn := :occn + 1;
                full_res := :full_res 
                            || MAP(LENGTH(:full_res), 0, '', ',')
                            || IFNULL(:part_res, '');
            else
                BREAK;
            end if;
        end while; -- occurrences

        -- if current matcher matched, don't apply the others
        if (:full_res !='') then
            BREAK;
        end if;

    end while; -- matchers  

    -- remove spaces
    location_text := replace (:full_res, ' ', '');
end;

С вашими тестовыми данными в таблице, подобной следующей:

drop table loc_data;
create column table loc_data ("CASE" integer primary key,
                            "INPUT_TEXT" NVARCHAR(2000));
-- PT and ST
insert into loc_data values (1, 'msdfmsfmdf PT2222, ST 43434 asdasdas');
-- Locations
insert into loc_data values (2, 'Locations 1, 2, 35 & 5 lkfaskjdlsaf .282 lkfdsklfjlkdsj 002');

Теперь вы можете просто запустить

select 
    *
    , extract_locators("INPUT_TEXT") as location_text
from 
    loc_data;

Чтобы получить

1 | msdfmsfmdf PT2222, ST 43434 asdasdas                        | PT2222,ST43434
2 | Locations 1, 2, 35 & 5 lkfaskjdlsaf .282 lkfdsklfjlkdsj 002 | 1,2,35,5

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

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

...