2

I have a string like this 'abc : efg : xyz' for a column in a table, all the records for this column will be like this. I want substring of this string after the last colon(:). Please do need ful help

example:

'abc : efg : xyz'  -> xyz  </br>

'abc : efg : efghj'-> efghj

I have query for this as below, but I want shorter then this query:

SELECT REPLACE (
          REGEXP_SUBSTR (
             'abc : efg : xyz',
             ':.*$',
             REGEXP_INSTR (
                'abc : efg : xyz',
                ':',
                1,
                  LENGTH ('abc : efg : xyz')
                - LENGTH (
                     REPLACE ('abc : efg : xyz',
                              ':',
                              NULL))),
             1),
          ': ') data_after_the_last_colon
  FROM DUAL

4 Answers 4

1

What you want is:

REGEXP_REPLACE (INPUTSTR, '^([^:]+ : )*', '')

Specifically, this seeks a string starting from the beginning (initial caret ^) with zero or more occurrences of a string with non-colons ([^:]+) followed by : . It replaces all of these leading strings terminated with the space-colon-space with an empty string.

The following query demonstrates how this works. I've used a factored subquery with your sample input and a half dozen other tests, and the query output has the input, my regexp_replace result, and your REPLACE (REGEXP_SUBSTR syntax (I replaced your ' abc : efg : xyz ' with the factored subquery). You can add another test case by duplicating the union all select line and changing the string for inputstr.

Oh, about doold -- your syntax couldn't handle an input string without a colon, it would throw an error that killed all query results. So I wrapped your syntax in a DECODE (doold to get all the rows back.

with sampl as (
  select           'abc : efg : xyz' as inputstr, 1 as doold from dual
  union all select 'z : b :' as inputstr, 1 as doold  from dual
  union all select 'z : b : ' as inputstr, 1 as doold  from dual
  union all select ' : a ' as inputstr, 1 as doold  from dual
  union all select ' a ' as inputstr, 0 as doold  from dual
  union all select '' as inputstr, 1 as doold  from dual
  union all select ' hij : klm : nop : qrs : tuv' as inputstr, 1 as doold  from dual
)
SELECT 
  inputstr,
  regexp_replace (inputstr, '^([^:]+ : )*', '') as bettr,
  decode (doold, 
      1, -- the following is your original expression, for comparison 
         -- purposes, edited only to replace 'abc : efg : xyz' with inputstr
         REPLACE (
          REGEXP_SUBSTR (
             inputstr,
             ':.*$',
             REGEXP_INSTR (
                inputstr,
                ':',
                1,
                  LENGTH (inputstr)
                - LENGTH (
                     REPLACE (inputstr,
                              ':',
                              NULL))),
             1),
          ': '),
          'Sorry the syntax won''t support input "' || inputstr || '"'
    ) data_after_the_last_colon
  FROM sampl
 order by doold desc, length (inputstr)
Sign up to request clarification or add additional context in comments.

Comments

1

As you say the pattern is fixed, reversing the string and looking for and getting a substring till the first semi-colon would be the easiest. You can also use trim to eliminate any leading/trailing spaces.

select reverse(substr(reverse('abc : efg : efghj'),
          1,instr(reverse('abc : efg : efghj'),':')-1)) from dual

5 Comments

Unfortunately REVERSE is undocumented in Oracle.
@JonHeller..Please go through this..docs.oracle.com/cd/E17952_01/refman-5.1-en/…
That document is for MySQL.
i suggest you try it for yourself
It works for now, on my system. But it may not work on other systems, or in the future. Oracle has shown a willingness to remove undocumented features regardless of their popularity. For example, WM_CONCAT was an undocumented but popular function, and was removed in 12c. If the function is not listed in one of the manuals it's probably not safe to use.
1

If the position parameter of the INSTR function is negative it will count back from the end of the string. So you could use something like this:

SELECT TRIM(SUBSTR('abc : efg : efghj',INSTR('abc : efg : efghj',':',-1) + 1))
FROM   dual;

Comments

1

Here you go. This works with NULL list elements too:

SQL> with tbl(row_nbr, str) as (
  2  select 1, 'abc : efg : xyz' from dual
  3  union
  4  select 2, 'abc : efg : efghj' from dual
  5  union
  6  select 3, 'abc :  : efghj' from dual
  7  )
  8  select row_nbr, regexp_substr(str, '(.*?)( : |$)', 1, regexp_count(str, ' \: ')+1, null, 1)
  9  from tbl
 10  order by row_nbr;

   ROW_NBR REGEXP_SUBSTR(STR
---------- -----------------
         1 xyz
         2 efghj
         3 efghj

SQL>

If you want to parse the entire list:

SQL> with tbl(row_nbr, str) as (
  2  select 1, 'abc : efg : xyz' from dual
  3  union
  4  select 2, 'abc : efg : efghj' from dual
  5  union
  6  select 3, 'abc :  : efghj' from dual
  7      )
  8  SELECT row_nbr, str,
  9             COLUMN_VALUE AS match_nbr,
 10            REGEXP_SUBSTR( str ,'(.*?)( : |$)', 1, COLUMN_VALUE, NULL, 1 ) AS match_value
 11     FROM   tbl,
 12            TABLE(
 13              CAST(
 14                MULTISET(
 15                  SELECT LEVEL
 16                  FROM   DUAL
 17                  CONNECT BY LEVEL <= REGEXP_COUNT( str ,' : ' )+1
 18                ) AS SYS.ODCINUMBERLIST
 19              )
 20            );

   ROW_NBR STR                MATCH_NBR MATCH_VALUE
---------- ----------------- ---------- -----------------
         1 abc : efg : xyz            1 abc
         1 abc : efg : xyz            2 efg
         1 abc : efg : xyz            3 xyz
         2 abc : efg : efghj          1 abc
         2 abc : efg : efghj          2 efg
         2 abc : efg : efghj          3 efghj
         3 abc :  : efghj             1 abc
         3 abc :  : efghj             2
         3 abc :  : efghj             3 efghj

9 rows selected.

SQL>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.