Замена всего, кроме определенного шаблона в строке (Oracle) - PullRequest
0 голосов
/ 16 октября 2019

Я хочу заменить все в строке на '', за исключением заданного шаблона с использованием Oracle regexp_replace.

В моем случае образец относится к немецким номерным знакам. Шаблоны содержатся в столбце использования (verwendungszweck_bez) таблицы доходов (банка). Шаблон может быть сопоставлен ([a-z]{1,3})[- ]([a-z]{1,2}) ?([0-9]{1,4}). Теперь я хотел бы изменить шаблон сопоставления, чтобы сопоставить все, кроме шаблона. Столбец использования выглядит следующим образом:

ALLIANZ VERSICHERUNGS-AG VERTRAG AS-9028000568 KFZ-VERSICHERUNG KFZ-VERS. XX-Y 427 01.01.19 - 31.12.19

XX-Y 427 будет интересующим меня шаблоном. Строка может содержать более одного номерного знака:

AXA VERSICHERUNG AG 40301089910 KFZ HAFTPFLICHT ABC-RM10 37,35 + 40330601383 KFZ HAFTPFLIVHT ABC-LX 283 21,19

В этомcase мне нужно ABC-RM10 и ABC-LX 283.

Пока я просто заменяю все из строки на regexp_replace:

regexp_replace(lower(a.verwendungszweck_bez),'^(.*?)kfz','')

, потому что всегда есть 'kfz' вСтрока и номерной знак информации (не обязательно прямой) после этого.

upper(regexp_replace(regexp_substr(regexp_replace(lower(a.verwendungszweck_bez),'(^(.*?)kfz',''),'([a-z]{1,3})[- ]([a-z]{1,2}) ?([0-9]{1,4})',1,1),'([a-z]{1,3})[- ]([a-z]{1,2}) ?([0-9]{1,4})','\1-\2 \3'))

Это работает, но я уверен, что есть лучшее решение.

Результатом должен быть список клиентов, номерные знаки и количество машин вроде этого:

Customer|licence plates         |count

1234567 |XX-Y 427| 1
1255599 |ABC-RM 10 + ABC-LX 283| 2

1 Ответ

1 голос
/ 16 октября 2019

Вы можете использовать рекурсивный подзапрос, чтобы найти элементы. Кроме того, вы можете использовать UPPER и TRANSLATE для нормализации данных, чтобы удалить необязательные разделители в номерных знаках и преобразовать их в один регистр:

Тестовые данные :

CREATE TABLE test_data ( value ) AS
SELECT 'ALLIANZ VERSICHERUNGS-AG VERTRAG AS-9028000568 KFZ-VERSICHERUNG KFZ-VERS. XX-Y 427 01.01.19 - 31.12.19' FROM DUAL UNION ALL
-- UNG AG 4030 should not match
SELECT 'AXA VERSICHERUNG AG 40301089910 KFZ HAFTPFLICHT ABC-RM10 37,35 + 40330601383 KFZ HAFTPFLIVHT ABC-LX 283 21,19' FROM DUAL UNION ALL
-- Multiple matches adjacent to each other
SELECT 'AA-A1BB-BB222CC C3333' FROM DUAL UNION ALL
-- Duplicate values with different separators and cases
SELECT 'AA-A1 AA-A 1 aa a1' FROM DUAL

Запрос :

WITH items ( value, item, next_pos ) AS (
  SELECT value,
         TRANSLATE( UPPER( REGEXP_SUBSTR( value, '([^a-z]|^)([a-z]{1,3}[- ][a-z]{1,2} ?\d{1,4})(\D|$)', 1, 1, 'i', 2 ) ), '_ -', '_' ),
         REGEXP_INSTR(  value, '([^a-z]|^)([a-z]{1,3}[- ][a-z]{1,2} ?\d{1,4})(\D|$)', 1, 1, 1, 'i', 2 ) - 1
  FROM   test_data
UNION ALL
  SELECT value,
         TRANSLATE( UPPER( REGEXP_SUBSTR( value, '([^a-z]|^)([a-z]{1,3}[- ][a-z]{1,2} ?\d{1,4})(\D|$)', next_pos, 1, 'i', 2 ) ), '_ -', '_' ),
         REGEXP_INSTR(  value, '([^a-z]|^)([a-z]{1,3}[- ][a-z]{1,2} ?\d{1,4})(\D|$)', next_pos, 1, 1, 'i', 2 ) - 1
  FROM   items
  WHERE  next_pos > 0
)
SELECT item,
       COUNT(*)
FROM   items
WHERE  item IS NOT NULL AND NEXT_POS > 0
GROUP BY item

Вывод :

ITEM     | COUNT(*)
:------- | -------:
CCC3333  |        1
AAA1     |        4
XXY427   |        1
ABCRM10  |        1
ABCLX283 |        1
BBBB222  |        1

db <> fiddle здесь

Результатом должен быть список клиентов ...

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


Обновление :

Если вам нужно количество уникальных номерных знаков на строку, то:

WITH items ( rid, value, item, next_pos ) AS (
  SELECT ROWID,
         value,
         TRANSLATE( UPPER( REGEXP_SUBSTR( value, '([^a-z]|^)([a-z]{1,3}[- ][a-z]{1,2} ?\d{1,4})(\D|$)', 1, 1, 'i', 2 ) ), '_ -', '_' ),
         REGEXP_INSTR(  value, '([^a-z]|^)([a-z]{1,3}[- ][a-z]{1,2} ?\d{1,4})(\D|$)', 1, 1, 1, 'i', 2 ) - 1
  FROM   test_data
UNION ALL
  SELECT rid,
         value,
         TRANSLATE( UPPER( REGEXP_SUBSTR( value, '([^a-z]|^)([a-z]{1,3}[- ][a-z]{1,2} ?\d{1,4})(\D|$)', next_pos, 1, 'i', 2 ) ), '_ -', '_' ),
         REGEXP_INSTR(  value, '([^a-z]|^)([a-z]{1,3}[- ][a-z]{1,2} ?\d{1,4})(\D|$)', next_pos, 1, 1, 'i', 2 ) - 1
  FROM   items
  WHERE  next_pos > 0
)
SELECT LISTAGG( item, ' + ' ) WITHIN GROUP ( ORDER BY item ) AS items,
       COUNT(*)
FROM   (
  SELECT DISTINCT
         rid,
         item
  FROM   items
  WHERE  item IS NOT NULL AND NEXT_POS > 0
)
GROUP BY rid;

Какие выходные данные:

ITEMS                    | COUNT(*)
:----------------------- | -------:
XXY427                   |        1
ABCLX283 + ABCRM10       |        2
AAA1 + BBBB222 + CCC3333 |        3
AAA1                     |        1

db <> fiddle здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...