How do I get substring after a character when the occurance of the character keeps changing - sql

Example
123\.456.578.910.ABC
123\.456.578.910
Expected result
123\.456.578
123\.456.578
For the both the inputs I should get only the first 3
I tried the regexp and substring and instr but I’m not getting the results

We can use REGEXP_SUBSTR here with a capture group:
SELECT REGEXP_SUBSTR(col, '^(\d+(\.\d+)*)', 1, 1, NULL, 1)
FROM yourTable;
Demo

Traditional, substr + instr combination is another option:
Sample data:
SQL> with test (col) as
2 (select '123\.456.578.910.ABC' from dual union all
3 select '123\.456.578.910' from dual
4 )
Query begins here:
5 select col,
6 substr(col, 1, instr(col, '.', 1, 3) - 1) result
7 from test;
COL RESULT
-------------------- --------------------
123\.456.578.910.ABC 123\.456.578
123\.456.578.910 123\.456.578
SQL>

If you value will always have at least 3 . characters then you can use:
SELECT value,
SUBSTR(value, 1, INSTR(value, '.', 1, 3) - 1) AS expected
FROM table_name;
If it may have fewer and you want the entire string in those cases then:
SELECT value,
CASE INSTR(value, '.', 1, 3)
WHEN 0
THEN value
ELSE SUBSTR(value, 1, INSTR(value, '.', 1, 3) - 1)
END AS expected
FROM table_name;
Which, for your sample data:
CREATE TABLE table_name (value) AS
SELECT '123\.456.578.910.ABC' FROM DUAL UNION ALL
SELECT '123\.456.578.910' FROM DUAL;
Both outputs:
VALUE
EXPECTED
123.456.578.910.ABC
123.456.578
123.456.578.910
123.456.578
db<>fiddle here

Related

Regex values after special character with empty values

I am struggle with regex to split spring into columns in Oracle database.
select (REGEXP_SUBSTR(replace('1:::9999', ' ',''), '[^: ]+', 1, 4)) from dual;
I need to obtain 4th value from that string as a column value, sometimes values at position 2,3 are empty and my query doesn't work. I am trying to figure out what regex will work
You can use
select (REGEXP_SUBSTR(replace('1:::9999', ' ',''), '([^: ]*)(:|$)', 1, 4, 'i', 1)) from dual;
Here, the ([^: ]*)(:|$) matches
([^: ]*) - Group 1: any zero or more chars other than : and space
(:|$) - Group 2, either : or end of string.
You do not need a (slower) regex for this task, use simple substr/instr functions:
with input_(val) as (
select '1:::9999' from dual
union all
select '1:2::' from dual
union all
select '1:2::3:5' from dual
)
, replaced as (
select input_.*, replace(val, ' ', '') as val_replaced
from input_
)
select
val,
substr(
val_replaced,
/*Locate the first occurrence of a colon and get a substring ...*/
instr(val_replaced, ':', 1, 3) + 1,
/*.. until the end, if the next colon is absent, or until the next colon*/
nvl(nullif(instr(val_replaced, ':', 1, 4), 0), length(val_replaced) + 1) - instr(val_replaced, ':', 1, 3) - 1
) as col
from replaced
VAL
COL
1:::9999
9999
1:2::
null
1:2::3:5
3
fiddle with performance difference.

Substring from underscore and onwards in Oracle

I have a string with under score and some characters. I need to apply substring and get values to the left excluding underscore. So I applied below formula and its working correctly for those strings which have underscore (_). But for strings without (_) it is bringing NULL. Any suggestions how this can be handled in the substring itself.
Ex: ABC_BASL ---> Works correctly; ABC ---> gives null
My formula as below -
select SUBSTR('ABC_BAS',1,INSTR('ABC_BAS','_')-1) from dual;
ABC
select SUBSTR('ABC',1,INSTR('ABC','_')-1) from dual;
(NULL)
You could use a CASE expression to first check for an underscore:
WITH yourTable AS (
SELECT 'ABC_BAS' AS col FROM dual UNION ALL
SELECT 'ABC' FROM dual
)
SELECT
CASE WHEN col LIKE '%\_%' ESCAPE '\'
THEN SUBSTR(col, 1, INSTR(col, '_') - 1)
ELSE col END AS col_out
FROM yourTable;
Use regular expression matching:
SELECT REGEXP_SUBSTR('ABC_BAS', '(.*)([_]|$)?', 1, 1, NULL, 1) FROM DUAL;
returns 'ABC', and
SELECT REGEXP_SUBSTR('ABC', '(.*)([_]|$)?', 1, 1, NULL, 1) FROM DUAL;
also returns 'ABC'.
db<>fiddle here
EDIT
The above gives correct results, but I missed the easiest possible regular expression to do the job:
SELECT REGEXP_SUBSTR('ABC_BAS', '[^_]*') FROM DUAL;
returns 'ABC', as does
SELECT REGEXP_SUBSTR('ABC', '[^_]*') FROM DUAL;
db<>fiddle here
Yet another approach is to use the DECODE in the length parameter of the substr as follows:
substr(str,
1,
decode(instr(str,'_'), 0, lenght(str), instr(str,'_') - 1)
)
You seem to want everything up to the first '_'. If so, one method usesregexp_replace():
select regexp_replace(str, '(^[^_]+)_.*$', '\1')
from (select 'ABC' as str from dual union all
select 'ABC_BAS' from dual
) s
A simpler method is:
select regexp_substr(str, '^[^_]+')
from (select 'ABC' as str from dual union all
select 'ABC_BAS' from dual
) s
Here is a db<>fiddle.
I'd use
regexp_replace(text,'_.*')
or if performance was a concern,
substr(text, 1, instr(text||'_', '_') -1)
For example,
with demo(text) as
( select column_value
from table(sys.dbms_debug_vc2coll('ABC', 'ABC_DEF', 'ABC_DEF_GHI')) )
select text
, regexp_replace(text,'_.*')
, substr(text, 1, instr(text||'_', '_') -1)
from demo;
TEXT REGEXP_REPLACE(TEXT,'_.*') SUBSTR(TEXT,1,INSTR(TEXT||'_','_')-1)
------------ --------------------------- -------------------------------------
ABC ABC ABC
ABC_DEF ABC ABC
ABC_DEF_GHI ABC ABC
Ok i think i got it. Add nvl to the substring and insert the condition as below -
select nvl(substr('ABC',1,instr('F4001Z','_')-1),'ABC') from dual;

REGEXP_SUBSTR SPLIT Function

i want to split this into 2019/GA/0000104
select REGEXP_SUBSTR('2019/0000015,2019/GA/0000104,2cdb376e-2966-4f24-9063-f4c6f31a6f35', '[^,]+')
from dual;
Output = 2019/GA/0000104
can u guys help?
It seems that you want to extract the second substring. If that's so, then you could use
regexp_substr (result), or
substr + inenter code herestr combination (result2)
SQL> with test (col) as
2 (select '2019/0000015,2019/GA/0000104,2cdb376e-2966-4f24-9063-f4c6f31a6f35' from dual)
3 select regexp_substr(col, '[^,]+', 1, 2) result,
4 --
5 substr(col, instr(col, ',', 1, 1) + 1,
6 instr(col, ',', 1, 2) - instr(col, ',', 1, 1) - 1
7 ) result2
8 from test;
RESULT RESULT2
--------------- ---------------
2019/GA/0000104 2019/GA/0000104
SQL>
Try using REGEXP_SUBSTR with a capture group:
SELECT
REGEXP_SUBSTR(input, ',(.*),', 1, 1, NULL, 1)
FROM yourTable;
Demo
This form of the regex returns the second occurrence of a string of characters that are followed by a comma or the end of the line. It returns the correct element if the first one should ever be NULL.
with tbl(str) as (
select '2019/0000015,2019/GA/0000104,2cdb376e-2966-4f24-9063-f4c6f31a6f35' from dual
)
select regexp_substr(str, '(.*?)(,|$)', 1, 2, NULL, 1)
from tbl;

Oracle regex substring

I am trying to get the value between two semi colons.
select (REGEXP_SUBSTR(col,'[^:]+',1,2,null)) from test
These are the rows I am dealing with:
1236:10:EXEC
1236::EXEC
In my result set, I want to get:
10
<null>
The query above returns:
10
EXEC
You can avoid regexp for this; for example:
select substr(col, instr(col, ':') +1, instr(col, ':', 1, 2) - instr(col, ':') -1)
from test
How it works:
select instr(col, ':') as firstColon,
instr(col, ':', 1, 2) as secondColon,
instr(col, ':', 1, 2) - instr(col, ':') -1 as lengthOfResultingString,
substr(col, instr(col, ':') +1, instr(col, ':', 1, 2) - instr(col, ':') -1) as result
from test
gives:
FIRSTCOLON SECONDCOLON LENGTHOFRESULTINGSTRING RESULT
---------- ----------- ----------------------- ------------
5 8 2 10
5 6 0
This assumes that you always have at least two colon characters in the string.
With regexp, in a slower, but more compact way, you could use:
regexp_substr(col, ':([^:]*):', 1, 1, null, 1)
with test (col) as
(
select '1236:10:EX' from dual union all
select '1543::Ex' from dual
)
select regexp_replace(col, '(:(.*):)|.', '\2') from test;
Use regexp_substr like this to handle NULL list elements. The 4th argument is the element in the list you want:
with test (col) as
(
select '1236:10:EX' from dual union all
select '1543::Ex' from dual
)
select regexp_substr(col, '(.*?)(:|$)', 1, 2, NULL, 1) from test;

Substring from string oracle

I have strings : 'A-20-1-1', 'A-10-10', 'A-10-11-1'
And result from substringing:
'A-20-1-1', 'A-10-10', 'A-10-11-1'
1 10 11
Code won't works fine:
Select Substr(string, instr(string,'-',1,2)+1, instr(string, '-',1,2)-1)
From dual;
At the beginning I find second '-', than next one if exists. If not I get string length.
create table a(b varchar2(20));
insert into a values('A-20-1-1');
insert into a values('A-10-10');
insert into a values('A-10-11-1');
Select
b,
substr(b,instr(b,'-',1,2)+1,decode(instr(b,'-',1,3),0,length(b)-instr(b,'-',1,2),instr(b,'-',1,3)-instr(b,'-',1,2)-1)) z
from a;
gives us what you need:
A-20-1-1 1
A-10-10 10
A-10-11-1 11
At first I find the second - sign position, and then get a substring of the value from this position to the rest of the value. Then I exclude the part of the string from previous step if the string has the - sign. Like this:
with t(d) as (
select 'A-20-1-1' from dual union all
select 'A-10-10-4' from dual union all
select 'A-10-11-1' from dual
)
select REPLACE(SUBSTR(d, INSTR(d, '-', 1, 2) + 1), SUBSTR(d, INSTR(d, '-', 1, 3))) from t
RES
---
1
10
11