Oracle sql : get only specific part of a substring - sql

I'm struggling with a query in Oracle SQL, wanting to get some timings out of some text stored in an Oracle db.
Table :
kde_test (myString varchar(50))
Table contents (3 records):
'task1 - 6m'
'task2 - 66m'
'task3 - 666m'
I would like to get only the interesting part of the string, being the timings, so I would like to get only '6', '66' & '666' as results.
Searched this forum a bit, and got up with this query eventually, but it seems I do not completely get it, as the results it returns are :
6m
66m
666m
select
CASE
WHEN myString like 'task1%' THEN substr(myString,9,INSTR(myString,'m',1,1)-1)
WHEN myString like 'task2%' THEN substr(myString,9,INSTR(myString,'m',1,1)-1)
WHEN myString like 'task3%' THEN substr(myString,9,INSTR(myString,'m',1,1)-1)
END
from kde_test
where myString like 'task%'
EDIT :
Since some solutions (thanks already for quick response) take into account the specific values (eg. all 3 records ending on '6m'), maybe it best to take into account the values could be :
Table contents (3 records):
'task1 - 6m'
'task2 - 58m'
'task3 - 123m'

you can use this way too
select regexp_replace(SUBSTR('task3 - 666m' ,
INSTR('task3 - 666m', '-',1, 1)+1, length('task3 - 666m')), '[A-Za-z]')
from dual
result :666

Use SUBSTR and INSTR and make it dynamic.
SUBSTR(str,
instr(str, ' - ', 1, 1) +3,
instr(str, 'm', 1, 1) -
instr(str, ' - ', 1, 1) -3
)
For example,
SQL> WITH DATA AS(
2 SELECT 'task1 - 6m' str FROM dual UNION ALL
3 SELECT 'task2 - 66m' str FROM dual UNION ALL
4 SELECT 'task3 - 666m' str FROM dual UNION ALL
5 SELECT 'task4 - 58m' str FROM dual UNION ALL
6 SELECT 'task5 - 123m' str FROM dual
7 )
8 SELECT str,
9 SUBSTR(str, instr(str, ' - ', 1, 1) +3,
10 instr(str, 'm', 1, 1) - instr(str, ' - ', 1, 1) -3) new_st
11 FROM DATA;
STR NEW_STR
------------ ------------
task1 - 6m 6
task2 - 66m 66
task3 - 666m 666
task4 - 58m 58
task5 - 123m 123
SQL>

You can use the regex_substr function. \d+ means one or more digits, and $ anchors the end of the string.
select regexp_substr(str, '\d+m$')
from mytable
Example at SQL Fiddle.

In order to correct your current query, you should change the following string - "INSTR(myString,'m',1,1)-1" to "INSTR(myString,'m',1,1)-9".
However, the other answers provided above seem like a more elegant solution to your problem.
I did feel the need to publish this just to clarify what wasn't working well in current query - in INSTR function returns the position of the m letter, and then used as the length of the string to print. What my fix does is telling the query to print everything from the 9th character until the position of the m letter, which results in the task time required.

I have tried to divide this into two parts
First pick the string after -
regexp_substr ('task1 - 1234m', '[^ _ ]+',1, 3) --results 1234m
Fetch the number part of the string fetched from output of first
regexp_substr(regexp_substr ('task1 - 1234m', '[^ _ ]+',1, 3),'[[:digit:]]*')
--output 1234
So,the final query is
SELECT regexp_substr(regexp_substr (mystring, '[^ _ ]+',1, 3),'[[:digit:]]*')
FROM kde_test;

Use This:-
select substr(replace(myString,'m',''),9) output
from kde_test
where myString like 'task%'

Related

shorten the string to the desired values

I have a table with a "Link" attribute. It has the following meaning:
INC102
INC1020
INC10200
I want to get the following result:
INC102
INC1020
INC10200
I need to leave the INC and the numbers after it without .
Tell me which command will help here? Since I understand that "Substr" will not work here.
I am use SQL Developer - Oracle
If you just want to extract "INC" with the following digits, use regexp_substr():
select regexp_substr(link, 'INC[0-9]+')
Here is a db<>fiddle.
Since I understand that "Substr" will not work here.
Says who?
SQL> with test (col) as
2 (select 'INC102' from dual union all
3 select 'INC1020' from dual union all
4 select 'INC10200' from dual
5 )
6 select
7 substr(col,
8 instr(col, '>') + 1,
9 instr(col, '<', instr(col, '>')) - instr(col, '>') - 1
10 ) result
11 from test;
RESULT
------------------------------------------------------------------------------------------------------------------------
INC102
INC1020
INC10200
SQL>
What does it do?
lines #1 - 5: sample data
line #8: starting point of the SUBSTR function is one character after the first > sign
line #9: length (used as the 3rd parameter of the SUBSTR) is position of the first < that follows the first > minus position of the first >
And that's it ... why wouldn't it work?
You could treat [<>] as the word delimiter and take the second word:
with test (col) as
( select 'INC102' from dual union all
select 'INC1020' from dual union all
select 'INC10200' from dual
)
select regexp_substr(col,'[^<>]+', 1, 2)
from test;
REGEXP_SUBSTR(COL,'[^<>]+',1,2)
-------------------------------
INC102
INC1020
INC10200

Need to remove the exact group of characters

I need to remove all the characters after a particular string (-->).
select
REGEXP_SUBSTR('-->Team Name - Red-->blue', '[^(-->)]+')
from dual;
expected result from the above query is "Team Name - Red". But its returning "Team Name".
Its filtering out everything whenever it matches any of one character.
You can still use Regexp_Substr() analytic function :
Select Regexp_Substr('-->Team Name - Red-->blue',
'-{2}>(.*?)-{2}>',1,1,null,1) as "Result"
From dual;
Result
---------------
Team Name - Red
-{2}> ~ exactly twice occurence of - and single occurence of > e.g. ( --> )
(.*?) ~ matches anything delimited by the pattern above
Demo
You could try using REGEXP_REPLACE here with a capture group:
SELECT
REGEXP_REPLACE('-->Team Name - Red-->blue', '.*-->(.*?)-->.*', '\1')
FROM dual;
The output from this is Team Name - Red
Demo
It seems that you, actually, want to return string between two --> marks. A good, old substr + instr option would be
SQL> with test (col) as
2 (select '-->Team Name - Red-->blue' from dual)
3 select substr(col,
4 instr(col, '-->', 1, 1) + 3,
5 instr(col, '-->', 1, 2) - instr(col, '-->', 1, 1) - 3
6 ) result
7 from test;
RESULT
---------------
Team Name - Red
SQL>

Oracle - Extract multiple substrings from a string

I need to extract all e-mail accounts mentioned on a single string, so far I've tried with SUBSTR and INSTR, but with no success, here an example:
The string looks like this:
()
string = "User_1" {user_1#domain.com};"User_2" {user_2#domain.com};"User_3" {user_3#domain.com};"User_4" {user_4#domain.com};
select SUBSTR(string ,INSTR(string ,'<',-1,2)) EMAIL
from dual;
What I need is something like this:
user_1#domain.com;user_2#domain.com;user_3#domain.com;user_4#domain.com;
Looking for the preceding { and the following }; which seems to appear in your string you can use:
SELECT REGEXP_REPLACE(
'"User_1" {user_1#domain.com};"User_2" {user_2#domain.com};"User_3" {user_3#domain.com};"User_4" {user_4#domain.com};',
'.*?\{(.*?)\};',
'\1;'
) AS emails
FROM DUAL;
Output:
EMAILS
------------------------------------------------------------------------
user_1#domain.com;user_2#domain.com;user_3#domain.com;user_4#domain.com;
Something like this will work for a single input string. It can be adapted to work with more than one input string.
with
inputs (str) as (
select '"User_1" {user_1#domain.com};"User_2" {user_2#domain.com};"User_3" {user_3#domain.com};"User_4" {user_4#domain.com};'
from dual
)
select level as ord,
substr(str, instr(str, '{', 1, level) + 1,
instr(str, '}', 1, level) - instr(str, '{', 1, level) - 1) as email
from inputs
connect by level <= length(str) - length(replace(str, '{'))
;
ORD EMAIL
--- -----------------
1 user_1#domain.com
2 user_2#domain.com
3 user_3#domain.com
4 user_4#domain.com
From this site I found this nasty bit of regex:
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")#(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
But, it seems to work! I cannot break down what it's doing for you though :P
Here's an example on regexr
EDIT: That is giving errors in Oracle, so I've written up a new one:
([a-zA-Z0-9.\-_])+\#[a-zA-Z]+\.[a-zA-Z.]+
Here's an example of the new one in regexr

SQL substr function

in my table one column contains data as below
BMS/430301420-XN/0
I need to use substr function in oracle and output to be taken as
430301420-XN
the one I used is as below
substr(buy_id,5),substr(substr(buy_id,5),instr(buy_id,'/',2))
but it is not working please help me
If you know the format of the string and you always want to start on the fifth character and remove the last two, then:
select substr(str, 5, -2)
If you just want the part between the slashes, then use regexp_substr():
select replace(regexp_substr(str, '/.*/'), '/', '')
Easiest way is a Regular Expression, find the string between the slashes but don't include them in the result:
regexp_substr(buy_id, '(?<=/).*(?=/)')
With a combination of SUBSTR and INSTR:
SQL> WITH DATA AS(
2 SELECT 'BMS/430301420-XN/0' str FROM dual UNION ALL
3 SELECT 'BMSABC/430301420-XN/0' str FROM dual UNION ALL
4 SELECT 'BMS/430301420-XN/012345' str FROM dual
5 )
6 SELECT str,
7 SUBSTR(str, instr(str, '/', 1, 1)+1, instr(str, '/', 1, 2)
8 -instr(str, '/', 1, 1)-1) new_str
9 FROM DATA;
STR NEW_STR
----------------------- -----------------------
BMS/430301420-XN/0 430301420-XN
BMSABC/430301420-XN/0 430301420-XN
BMS/430301420-XN/012345 430301420-XN
SQL>
The above uses the logic to find the substring between the first and second occurrence of the /.
This will also Work :D
select Column_Name as OLD , substr(''||to_char(Column_Name)||'',instr
(''||to_char(Column_Name)||'','/',1)+1,(instr(''||to_char(Column_Name)
||'','/',1,2)-instr(''||to_char(Column_Name)||'','/',1,1)-1)) as NEW from Table_Name;
Same Use Of substr and instr
my answer is :
select
substr('BMS/430301420-XN/0',
(instr('BMS/430301420-XN/0','/') +1),
(instr('BMS/430301420-XN/0','/',(instr('BMS/430301420-XN/0','/')+1))-instr('BMS/430301420-XN/0','/')-1 ))
from dual
you can see this sample :
http://www.sqlfiddle.com/#!4/9eecb7/863/0

Split String by delimiter position using oracle SQL

I have a string and I would like to split that string by delimiter at a certain position.
For example, my String is F/P/O and the result I am looking for is:
Therefore, I would like to separate the string by the furthest delimiter.
Note: some of my strings are F/O also for which my SQL below works fine and returns desired result.
The SQL I wrote is as follows:
SELECT Substr('F/P/O', 1, Instr('F/P/O', '/') - 1) part1,
Substr('F/P/O', Instr('F/P/O', '/') + 1) part2
FROM dual
and the result is:
Why is this happening and how can I fix it?
Therefore, I would like to separate the string by the furthest delimiter.
I know this is an old question, but this is a simple requirement for which SUBSTR and INSTR would suffice. REGEXP are still slower and CPU intensive operations than the old subtsr and instr functions.
SQL> WITH DATA AS
2 ( SELECT 'F/P/O' str FROM dual
3 )
4 SELECT SUBSTR(str, 1, Instr(str, '/', -1, 1) -1) part1,
5 SUBSTR(str, Instr(str, '/', -1, 1) +1) part2
6 FROM DATA
7 /
PART1 PART2
----- -----
F/P O
As you said you want the furthest delimiter, it would mean the first delimiter from the reverse.
You approach was fine, but you were missing the start_position in INSTR. If the start_position is negative, the INSTR function counts back start_position number of characters from the end of string and then searches towards the beginning of string.
You want to use regexp_substr() for this. This should work for your example:
select regexp_substr(val, '[^/]+/[^/]+', 1, 1) as part1,
regexp_substr(val, '[^/]+$', 1, 1) as part2
from (select 'F/P/O' as val from dual) t
Here, by the way, is the SQL Fiddle.
Oops. I missed the part of the question where it says the last delimiter. For that, we can use regex_replace() for the first part:
select regexp_replace(val, '/[^/]+$', '', 1, 1) as part1,
regexp_substr(val, '[^/]+$', 1, 1) as part2
from (select 'F/P/O' as val from dual) t
And here is this corresponding SQL Fiddle.