noobie2023
noobie2023

Reputation: 783

Oracle: find the largest number within one string

I have some strings within a column of a table like asdfAB98:(hjkl,)AB188(uiop)uuuAB78:jknd. I am wondering how may I extract the largest number within such a string in each row. For example, here the largest number is 188 (out of 188, 98 and 78).

Since the numbers I'm interested in are always right after AB, I was thinking about using regexp_substr. Unfortunately, I'm not sure how to have it output multiple rows so that I can use max clause. PLSQL language would be great as well. Please show me a simple example if you have an idea. Thank you in advance!

Upvotes: 0

Views: 855

Answers (2)

Littlefoot
Littlefoot

Reputation: 142705

Alternatively (to Alex' answer), if there are multiple rows:

SQL> with your_table (id, str) as (
  2    select 1, 'sdfAB98:(hjkl,)AB188(uiop)uuuAB78:jknd' from dual
  3    union all select 2, '123abc456abc78d9' from dual
  4  )
  5  select id, max(to_number(regexp_substr(str, '\d+', 1, column_value))) max_num
  6  from your_table,
  7       table(cast(multiset(select level from dual
  8                           connect by level <= regexp_count(str, '\d+')
  9                          ) as sys.odcinumberlist))
 10  group by id;

        ID    MAX_NUM
---------- ----------
         1        188
         2        456

SQL>

Upvotes: 1

Alex Poole
Alex Poole

Reputation: 191265

You could tokenize the string into all its number components, and then find the maximum:

select max(to_number(
    regexp_substr('sdfAB98:(hjkl,)AB188(uiop)uuuAB78:jknd', '(\d+)', 1, level))
  ) as max_value
from dual
connect by regexp_substr('sdfAB98:(hjkl,)AB188(uiop)uuuAB78:jknd', '(\d+)', 1, level)
  is not null;

 MAX_VALUE
----------
       188

or

select max(to_number(
    regexp_substr('sdfAB98:(hjkl,)AB188(uiop)uuuAB78:jknd', '(\d+)', 1, level, null, 1))
  ) as max_value
from dual
connect by level <= regexp_count('sdfAB98:(hjkl,)AB188(uiop)uuuAB78:jknd', '\d+');

 MAX_VALUE
----------
       188

If you need to get values from multiple rows you need the connect-by to match the IDs, and also need to include a reference to a non-deterministic function to prevent looping; with two values in a CTE:

with your_table (id, str) as (
  select 1, 'sdfAB98:(hjkl,)AB188(uiop)uuuAB78:jknd' from dual
  union all select 2, '123abc456abc78d9' from dual
)
select id, max(to_number(regexp_substr(str, '(\d+)', 1, level, null, 1))) as max_value
from your_table
connect by prior id = id
and prior dbms_random.value is not null
and level <= regexp_count(str, '\d+')
group by id;

        ID  MAX_VALUE
---------- ----------
         1        188
         2        456

Upvotes: 3

Related Questions