PL / SQL поиск Regex как по символам, так и по цифрам - PullRequest
2 голосов
/ 10 июля 2020

У меня есть таблица TA, в которой есть столбец inv_ref с данными, как показано ниже.

inv_ref
----------
MX/3280/20
CT/3281/20
CT/3109/20
MX/3272/20
RF/3275/20

Мое требование - получить, тогда как среднее 4 di git число inv_ref между От 3270 до 3299 также начинается с MX и CT .

select * from TA where regexp_like(inv_ref, 'CT/32[7-9][0-9]/20')

Вышеуказанный запрос возвращает только CT , как можно вернуть как CT , так и MX связанные значения без RF ?

Ответы [ 4 ]

4 голосов
/ 10 июля 2020

Вы можете использовать:

SELECT *
FROM   TA
WHERE  REGEXP_LIKE(inv_ref, '^(CT|MX)/32[7-9][0-9]/20$')

Затем, если у вас есть тестовые данные:

CREATE TABLE TA ( inv_ref, is_valid ) AS
SELECT 'MX/3280/20', 'Valid' FROM DUAL UNION ALL
SELECT 'CT/3281/20', 'Valid' FROM DUAL UNION ALL
SELECT 'CT/3109/20', 'Invalid, number too low' FROM DUAL UNION ALL
SELECT 'MX/3272/20', 'Valid' FROM DUAL UNION ALL
SELECT 'RF/3275/20', 'Invalid, wrong start' FROM DUAL UNION ALL
SELECT 'CX/3299/20', 'Invalid, wrong start' FROM DUAL UNION ALL
SELECT 'MT/3270/20', 'Invalid, wrong start' FROM DUAL UNION ALL
SELECT 'ACT/3270/20', 'Invalid, wrong start' FROM DUAL;

Это выводит:

INV_REF    | IS_VALID
:--------- | :-------
MX/3280/20 | Valid   
CT/3281/20 | Valid   
MX/3272/20 | Valid   

db <> fiddle здесь

3 голосов
/ 10 июля 2020

Было бы намного проще добавить виртуальные сгенерированные столбцы:

alter table your_table add (
  P1 generated always as (regexp_substr(inv_ref,'^[^/]+')),
  P2 generated always as (to_number(regexp_substr(inv_ref,'/(\d+)/',1,1,null,1))),
  P3 generated always as (regexp_substr(inv_ref,'[^/]+$'))
);

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

Полный тестовый пример:

CREATE TABLE YOUR_TABLE ( inv_ref ) AS
SELECT 'MX/3280/20' FROM DUAL UNION ALL
SELECT 'CT/3281/20' FROM DUAL UNION ALL
SELECT 'CT/3109/20' FROM DUAL UNION ALL
SELECT 'MX/3272/20' FROM DUAL UNION ALL
SELECT 'RF/3275/20' FROM DUAL UNION ALL
SELECT 'CX/3299/20' FROM DUAL UNION ALL
SELECT 'MT/3270/20' FROM DUAL UNION ALL
SELECT 'ACT/3270/20' FROM DUAL;

alter table your_table add (
  P1 generated always as (regexp_substr(inv_ref,'^[^/]+')),
  P2 generated always as (to_number(regexp_substr(inv_ref,'/(\d+)/',1,1,null,1))),
  P3 generated always as (regexp_substr(inv_ref,'[^/]+$'))
);

select * from your_table
where p1 IN ('CT', 'MX')
  and p2 BETWEEN 3270 and 3299;

Результат:

MX/3280/20  MX        3280 20
CT/3281/20  CT        3281 20
MX/3272/20  MX        3272 20
1 голос
/ 10 июля 2020

Вы можете использовать

SQL> create table my_test ( inv_ref varchar2(100) ) ;

SQL> insert into my_test values ( 'MX/3280/20') ;

SQL> insert into my_test values ( 'CD/3281/20') ;

SQL> insert into my_test values ( 'CD/3109/20') ;

SQL> insert into my_test values ( 'MX/3272/20') ;

SQL> insert into my_test values ( 'RF/3275/20') ;

Table created.

SQL> SQL> SQL>
1 row created.

SQL> SQL>
1 row created.

SQL> SQL>
1 row created.

SQL> SQL>
1 row created.

SQL> SQL>

1 row created.

SQL> commit ;

Commit complete.

Два варианта (в моем случае я использую CD вместо CT). Эта опция будет работать, пока строки ограничены примером. Если у вас будет другая комбинация, ее не будет, поскольку CD | MX означает C или D, или M, или X ). См. Комментарии к ответу. @MTO, спасибо за комментарии.

SQL> select * from my_test where regexp_like(inv_ref, '[CD|MX]/32[7-9][0-9]/20')

INV_REF
--------------------------------------------------------------------------------
MX/3280/20
CD/3281/20
MX/3272/20


SQL> select * from my_test where regexp_like(inv_ref, 'CD/32[7-9][0-9]/20') or 
regexp_like(inv_ref, 'MX/32[7-9][0-9]/20')

INV_REF
--------------------------------------------------------------------------------
MX/3280/20
CD/3281/20
MX/3272/20
0 голосов
/ 10 июля 2020

Вы можете использовать значения, разделенные | (или) следующим образом:

select * from TA where regexp_like(inv_ref, '^(CT|MX)/32[7-9][0-9]/20');

db <> fiddle

...