If you want to match complete terms in a comma-delimited string then you can use:
SELECT code,
REGEXP_SUBSTR(code, '(^|,)(p\d{6})-(,|$)', 1, 1, NULL, 2) AS result
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (code) as
SELECT 'p700401-' FROM DUAL UNION ALL
SELECT 'p791701-' FROM DUAL UNION ALL
SELECT '100-,p788001-,' FROM DUAL UNION ALL
SELECT '123-,p456789-xyz,p987654-' FROM DUAL UNION ALL
SELECT 'p111111-,p222222-not_this,p333333-,p444444-' FROM DUAL;
Outputs:
| CODE |
RESULT |
| p700401- |
p700401 |
| p791701- |
p791701 |
| 100-,p788001-, |
p788001 |
| 123-,p456789-xyz,p987654- |
p987654 |
| p111111-,p222222-not_this,p333333-,p444444- |
p111111 |
Displaying multiple terms
If you want to remove the non-matching terms from the string then:
SELECT code,
LTRIM(
REGEXP_REPLACE(
',' || REPLACE(code, ',', ',,') || ',',
'((,p\d{6})-,)|,.*?,',
'\2'
),
','
) AS result
FROM table_name;
Which, outputs:
| CODE |
RESULT |
| p700401- |
p700401 |
| p791701- |
p791701 |
| 100-,p788001-, |
p788001 |
| 123-,p456789-xyz,p987654- |
p987654 |
| p111111-,p222222-not_this,p333333-,p444444- |
p111111,p333333,p444444 |
And if you want to split the list into rows then:
SELECT t.code,
i.*
FROM (
SELECT code,
',' || REPLACE(code, ',', ',,') || ',' AS double_delims
FROM table_name
) t
INNER JOIN LATERAL (
SELECT LEVEL As item,
REGEXP_SUBSTR(double_delims, ',(p\d{6})-,|,(.*?),', 1, LEVEL, NULL, 1)
AS value
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT(double_delims, ',(p\d{6})-,|,(.*?),')
) i
ON (i.value IS NOT NULL);
Which outputs:
| CODE |
ITEM |
VALUE |
| p700401- |
1 |
p700401 |
| p791701- |
1 |
p791701 |
| 100-,p788001-, |
2 |
p788001 |
| 123-,p456789-xyz,p987654- |
3 |
p987654 |
| p111111-,p222222-not_this,p333333-,p444444- |
1 |
p111111 |
| p111111-,p222222-not_this,p333333-,p444444- |
3 |
p333333 |
| p111111-,p222222-not_this,p333333-,p444444- |
4 |
p444444 |
fiddle