简体   繁体   中英

How to select the list of words containing a particular substring as part of a SQL query (oracle)?

I'm trying to return the list of "words" (separated by spaces) containing a certain substring within a string as part of an Oracle Sql query. Would like to return the result as a comma separated list. Separate rows for each match would also work.

Example String in [text_col] field:

some words 123-asdf-789A and also this one 456-asdf-555A more words etc.

Desired result: 123-asdf-789A, 456-asdf-555A

This is what I have so far but it only returns the first result and the fact that it's two separate regular expressions makes it difficult to concatenate all matches as I would like to do.

CONCAT(REGEXP_SUBSTR(text_col, ''(([^[:space:]]+)\asdf)'', 1, 1, ''i'', 1), 
REGEXP_SUBSTR(text_col, ''\asdf([^[:space:]]+)'', 1, 1, ''i'', 1))

You can use some regexp functions together as :

with tab(str) as
(
 select 'some words 123-asdf-789A and also this one 456-asdf-555A more words etc' from dual
), t as 
(
select regexp_substr(str,'[^[:space:]]+',1,level) as str, level as lvl
  from tab
connect by level <= regexp_count(str,'[:space:]')  
)
select listagg(str,',') within group (order by lvl) as "Result"
  from t
 where regexp_like(str,'-');

Result
---------------------------------
123-asdf-789A,456-asdf-555A

Demo

first split by spaces (through [:space:] posix) and take the ones containing dash characters, and finally concatenate by listagg() function

Use a recursive sub-query factoring clause and iterate through all the matches concatenating the string as you go:

Oracle Setup :

CREATE TABLE test_data ( value ) AS
SELECT 'some words 123-asdf-789A and also this one 456-asdf-555A more words etc.' FROM DUAL UNION ALL
SELECT 'some words without the expected sub-string' FROM DUAL UNION ALL
SELECT 'asdf asdf-123 456-asdf 78-asdf-90' FROM DUAL

Query :

WITH matches ( value, idx, cnt, match ) AS (
  SELECT value,
         0,
         REGEXP_COUNT( value, '\S*asdf\S*' ),
         CAST( NULL AS VARCHAR2(4000) )
  FROM   test_data
UNION ALL
  SELECT value,
         idx + 1,
         cnt,
         CASE idx WHEN 0 THEN '' ELSE match || ' ' END
           || REGEXP_SUBSTR( value, '\S*asdf\S*', 1, idx + 1 )
  FROM   matches
  WHERE  idx < cnt
)
SELECT value, match
FROM   matches
WHERE  idx = cnt;

Output :

\nVALUE | MATCH                            \n:----------------------------------------------------------------------- |  :-------------------------------- \nsome words without the expected sub-string | null                             \nsome words 123-asdf-789A and also this one 456-asdf-555A more words etc. | 123-asdf-789A 456-asdf-555A       \nasdf asdf-123 456-asdf 78-asdf-90 |  asdf asdf-123 456-asdf 78-asdf-90 \n

db<>fiddle here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM