Sql Oracle: Regexp_substr - sql

I have the following expression:
15-JUL-16,20-JUL-16,20-JUL-16,30-JUL-16 in one of my columns.
I successfully used SUBSTR(REGEXP_SUBSTR(base.systemdate, '.+,'), 1, 9) to get 15-JUL-16 (expression until first comma) from the expression.
But I can't figure out how to get 30-JUL-16 (the last expression after last comma).
Is there some way to use REGEXP_SUBSTR to get that? And since we are at it.
Is there a neat way to only use REGEXP_SUBSTR to get 15-JUL-16 without comma? Because I am using second SUBSTR to get rid of the comma, so I can get it compatible with data format.

You can use a very similar construct:
SELECT REGEXP_SUBSTR(base.systemdate, '[^,]+$')
Oracle (and regular expressions in general) are "greedy". This means that they take the longest string. If you know the items in the list are all the same length, you could just use:
SELECT SUBSTR( ase.systemdate, -9)

Try this
select dates from
(
SELECT dates,max(id) over (partition by null) lastrec,min(id) over (partition by null) firstrec,id FROM (
with mine as(select '15-JUL-16,20-JUL-16,20-JUL-16,30-JUL-16' hello from dual)
select rownum id,regexp_substr(hello, '[^,]+', 1, level) dates from mine
connect by regexp_substr(hello, '[^,]+', 1, level) is not null)
)
where id=firstrec or id=lastrec
this query give you first and last record from comma separated list.

Related

Oracle String Replace With Multiple Values

I have one key/value comma separated string, and another keys-labels comma separated string as per the following example (ID/Name/Age):
key/value: 1=101,2=John,3=43
keys labels: ID,Name,Age
Result: ID=101,Name=John,Age=43
Is there a built in Oracle function (ex:regexp_replace) that can accomplish this?
I don't think there's a simple function, no. regexp_replace only replaces one value at a time, so to replace 3 values in a string, you need to loop over it 3 times.
It's possible to split the strings, use a connect by loop to replace each value, and then put the pairs back together, but it is a bit awkward. Example:
with t as (select '1=101,2=John,3=43' as pairs, 'ID,Name,Age' as labels from dual)
select
listagg(
regexp_replace(regexp_substr(pairs, '[^,]+', 1, level),
'\d+(.+)',
regexp_substr(labels, '[^,]+', 1, level) || '\1')
,',')
from t
connect by regexp_substr(pairs, '[^,]+', 1, level) is not null
See the link above for how to modify this query for a table with multiple rows and a unique key ID.
if the key values and labels length are fixed then you can get the result with replace function itself
select REPLACE(REPLACE( REPLACE('1=101,2=John,3=43', '1=','ID='),'2=','Name=') ,'3=','Age=') as finresult from dual ;
OUTPUT:
FINRESULT
ID=101,Name=John,Age=43

How do I dynamically extract substring from string?

I’m trying to dynamically extract a substring from a very long URL. For example, I may have the following URLs:
https://www.google.com/ABCDEF Version=“0.0.00.0” GHIJK
https://www.google.com/ABCDEFGH Version=“0.0.0.0” IJKLM
https://www.google.com/ABC Version=“0.0.0.00” 12345
I am trying to extract the version code only (0.0.0.0).
This is what I have so far:
SELECT SUBSTR(col, INSTR(col, ‘Version=“‘)+9)
FROM table
This query returns the following result:
0.0.00.0” GHIJK … (url continues on)
So, I attempt to find “Version” in the link, so I can start from the same position in each row. This works fine, however I’m having a hard time dynamically locating the ending quote (“). I tried using INSTR in the third parameter of my SUBSTR function, like so:
SELECT SUBSTR(col, INSTR(col, ‘Version=“‘)+9, INSTR(col, ‘“‘))
FROM table
I figured that this would find the position of the ending quote, and then use that number for the length, but it returns a strange output. I’ve also used POSITION, CHARINDEX, LENGTH, and LOCATE. None of these functions work in Oracle.
I think maybe when I put +9 after the first INSTR function, it’s setting the query to a fixed position instead of a dynamic one, but I’m not sure how else to remove ‘Version=“‘.
Here's one option (which, actually, selects what's between double quotes - that's version in your example; if there were some other similar substring, you'd get a wrong result).
with test (col) as
(select 'https://www.google.com/ABCDEF Version="0.0.00.0" GHIJK' from dual union all
select 'https://www.google.com/ABCDEFGH Version="0.0.0.0" IJKLM' from dual union all
select 'https://www.google.com/ABC Version="0.0.0.00" 12345' from dual
)
select col,
replace(regexp_substr(col, '".+"'), '"') version
from test;
which results in
https://www.google.com/ABCDEF Version="0.0.00.0" GHIJK 0.0.00.0
https://www.google.com/ABCDEFGH Version="0.0.0.0" IJKLM 0.0.0.0
https://www.google.com/ABC Version="0.0.0.00" 12345 0.0.0.00
You can still use use INSTR to locate the second " in the string, then subtract the location of the first " to get the length that you need to get. Below is an example query:
SELECT col,
SUBSTR (col, INSTR (col, '"') + 1, INSTR (col, '"', 1, 2) - INSTR (col, '"') - 1) version
FROM test;
You can use REGEXP_SUBSTR() with Version=(\d.*\d?) pattern in order to extract the piece between Version=" and "(your quotes are presumed to be regular double quotes " ")
SELECT REGEXP_SUBSTR(url,'Version="(\d.*\d)"',1,1,null,1) AS version
FROM t
where
the third argument(1) is position,
the fourth argument(1) is occurence, and especially important to use the last one as being capture group (1)
indeed using '"(\d.*\d)"' pattern is enough for the
current data set
or
REGEXP_REPLACE() with capture group \2 as
SELECT REGEXP_REPLACE(url,'^(.*Version=")([^"]*).*','\2') AS version
FROM t
Demo

ORACLE regexp_substr extract everything after specific char

How to get rest of string after specific char?
I have a string 'a|b|c|2|:x80|3|rr|' and I would like to get result after 3rd occurance of |. So the result should be like 2|:x80|3|rr|
The query
select REGEXP_SUBSTR('a|b|c|2|:x80|3|rr|','[^|]+$',1,4)
from dual
Returned me NULL
Use SUBSTR / INSTR combination
WITH t ( s ) AS (
SELECT 'a|b|c|2|:x80|3|rr|'
FROM dual
) SELECT substr(s,instr(s,'|',1,3) + 1)
FROM t;
Demo
REGEXP_REPLACE() will do the trick. Skip 3 groups of anything followed by a pipe, then replace with the 2nd group, which is the rest of the line (anchored to the end).
SQL> select regexp_replace('a|b|c|2|:x80|3|rr|', '(.*?\|){3}(.*)$', '\2') trimmed
2 from dual;
TRIMMED
------------
2|:x80|3|rr|
SQL>
I suggest a nice by long way by using regexp_substr, regexp_count and listagg together as :
select listagg(str) within group (order by lvl)
as "Result String"
from
(
with t(str) as
(
select 'a|b|c|2|:x80|3|rr|' from dual
)
select level-1 as lvl,
regexp_substr(str,'(.*?)(\||$)',1,level) as str
from dual
cross join t
connect by level <= regexp_count('a|b|c|2|:x80|3|rr|','\|')
)
where lvl >= 3;
Rextester Demo
If you use oracle 11g and above you can specify a subexpression to return like this:
select REGEXP_SUBSTR('a|b|c|2|:x80|3|rr|','([^|]+\|){3}(.+)$',1,1,null,2) from dual
Erkko,
You need to use the combination of SUBSTR and REGEXP_INSTR OR INSTR.
Your query will look like this. (Without Regex)
SELECT SUBSTR('a|b|c|2|:x80|3|rr|',INSTR('a|b|c|2|:x80|3|rr|','|',1,3)+1) from dual;
Your query will look like this. (With Regex as you want to use)
SELECT SUBSTR('a|b|c|2|:x80|3|rr|',REGEXP_INSTR('a|b|c|2|:x80|3|rr|','\|',1,3)+1) from dual;
Explanation:
First, you will need to find the place of the string you want as you mentioned. So in your case | comes at place 6. So that +1 would be your position to start to substring.
Second, from the original string, substring from that position+1 to unlimited.(Where your string ends)
Example:
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=6fd782db95f575201eded084493232ee

Using REGEXP_SUBSTR with Strings Qualifier

Getting Examples from similar Stack Overflow threads,
Remove all characters after a specific character in PL/SQL
and
How to Select a substring in Oracle SQL up to a specific character?
I would want to retrieve only the first characters before the occurrence of a string.
Example:
STRING_EXAMPLE
TREE_OF_APPLES
The Resulting Data set should only show only STRING_EXAM and TREE_OF_AP because PLE is my delimiter
Whenever i use the below REGEXP_SUBSTR, It gets only STRING_ because REGEXP_SUBSTR treats PLE as separate expressions (P, L and E), not as a single expression (PLE).
SELECT REGEXP_SUBSTR('STRING_EXAMPLE','[^PLE]+',1,1) from dual;
How can i do this without using numerous INSTRs and SUBSTRs?
Thank you.
The problem with your query is that if you use [^PLE] it would match any characters other than P or L or E. You are looking for an occurence of PLE consecutively. So, use
select REGEXP_SUBSTR(colname,'(.+)PLE',1,1,null,1)
from tablename
This returns the substring up to the last occurrence of PLE in the string.
If the string contains multiple instances of PLE and only the substring up to the first occurrence needs to be extracted, use
select REGEXP_SUBSTR(colname,'(.+?)PLE',1,1,null,1)
from tablename
Why use regular expressions for this?
select substr(colname, 1, instr(colname, 'PLE')-1) from...
would be more efficient.
with
inputs( colname ) as (
select 'FIRST_EXAMPLE' from dual union all
select 'IMPLEMENTATION' from dual union all
select 'PARIS' from dual union all
select 'PLEONASM' from dual
)
select colname, substr(colname, 1, instr(colname, 'PLE')-1) as result
from inputs
;
COLNAME RESULT
-------------- ----------
FIRST_EXAMPLE FIRST_EXAM
IMPLEMENTATION IM
PARIS
PLEONASM

sql Search a string between certain words

If the key word is "Find", is it possible to extract a string that is between the "Find"?
stackoverflow is awesome. FindHello, World!Find It has everything!
The result should be 'Hello, World!' because the string is between "Find"
My initial idea was to use Instr to locate two "Find", then locate what's between "Find".
Is there any better way to do this?
You can use either regular expressions or instr() to achieve what you're after.
I actually prefer regular expressions, if you're using version 10g or later, because I find doing multiple contortions with instr() fairly unwieldy, but it's up to you.
with phrases as (
select 'stackoverflow is awesome. FindHello, World!Find It has everything!' as phrase
from dual
)
select substr( phrase
, instr(phrase,'Find',1,1) + 4
, instr(phrase,'Find',1,2)
- instr(phrase,'Find',1,1)
- 4
)
from phrases
This gets the first and second occurrences of the string Find, starting from the first character, then uses these to work out the positions that you should be doing the sub-string on.
Alternatively, using regular expressions:
with phrases as (
select 'stackoverflow is awesome. FindHello, World!Find It has everything!' as phrase
from dual
)
select regexp_replace(phrase
, '([[:print:]]+Find)([[:print:]]+)(Find[[:print:]]+)', '\2')
from phrases
;
This takes any printable character multiple times, followed by the string Find etc. But, the main bit is the grouping (), which separates each part of the phrase. The \2 means that of the original matched string only the second group, i.e. that between the Find's is returned.
Here's a little SQL Fiddle to demonstrate.
This query suppose to handle more than two 'Find's
with SourceString as(
select 'Find123Find45345Find76876234Find87687Find' s_string
, 'Find' delimiter
from dual
)
select substr(s_string, f_f - s_f + length(delimiter), s_f-Length(delimiter ) )
from (select f_f
, s_f
from(select f_f
, f_f - lag(f_f, 1, f_f) over(order by 1) s_f
from (select Instr(s_string, delimiter , 1, level) f_f
from SourceString
connect by level <= Length(s_string))
)
where s_f > 0)
, SourceString