Oracle Update with Regular Expression - sql

I have some values in a column like:
"This is test $ABC variables."
I want to update all the variable definition to below one:
"This is test $ABC$ variables."
How can I write this update statement? Somehow, I couldn't manage.

Do you just want replace()?
update t
set col = replace(col, '$ABC', '$ABC$')
where col like '%$ABC%';

You may use this REGEXP query. The parentheses in '\$(\w+)' capture the word following $ in \1
SELECT REGEXP_REPLACE (
'This is test $ABC variables.This is a second variable $variable2.I have 100$',
'\$(\w+)',
'$\1$')
FROM DUAL;
O/p:
This is test $ABC$ variables.This is a second variable $variable2$.I have 100$

Unfortunately, I'm not good at regular expressions so this poor attempt of mine could probably be replaced by something smarter. Looking forward to see it!
SQL> with test as
2 (select 'This is test $ABC variables' col from dual union
3 select 'Stackoverflow says $DEF is so cool' from dual
4 )
5 select
6 col,
7 regexp_replace(col, '\$\w+', regexp_substr(col, '\$\w+') || '$') result
8 from test;
COL RESULT
---------------------------------- ----------------------------------------
Stackoverflow says $DEF is so cool Stackoverflow says $DEF$ is so cool
This is test $ABC variables This is test $ABC$ variables
SQL>

Related

Regex in Oracle - How can I check if a word does not occur?

I am currently using regex in Oracle to search a text for certain words. For example, if I want to search for the number of times "good performance" occurs, I want to exclude all sequences in which "not" appears. So I want to filter "good performance" and exclude "not good performance". On regex build pages it would work like this:
(?!not)+(good performance).
But unfortunately in my script it doesn't work. What would be the corresponding expression in Oracle?
Currently I used:
SELECT REGEXP_SUBSTR ('not good performance',
'(?!not)+(\sgood performance)',1,1,'i',2)
FROM DUAL
You can use:
SELECT value
FROM table_name
WHERE REGEXP_SUBSTR (
value,
'(not\s+)?(good performance)',
1,
1,
'i',
1
) IS NULL;
or, without regular expressions:
SELECT value
FROM table_name
WHERE LOWER(value) LIKE '%good performance%'
AND LOWER(value) NOT LIKE '%not good performance%';
Which, for the sample data:
CREATE TABLE table_name (value) AS
SELECT 'Good Performance' FROM DUAL UNION ALL
SELECT 'No, it is not. Good performance!' FROM DUAL UNION ALL
SELECT 'NOT GOOD PERFORMANCE' FROM DUAL;
Both output:
VALUE
Good Performance
No, it is not. Good performance!
fiddle
Do you really need regular expressions? How about instr?
SQL> with test (col) as
2 (select 'that is not good performance at all' from dual union all
3 select 'yes, it is good performance!' from dual
4 )
5 select *
6 from test
7 where instr(col, 'good performance') > 0
8 and instr(col, 'not good performance') = 0;
COL
-----------------------------------
yes, it is good performance!
SQL>

Need Regex pattern for right side of 10 digits from mobile Number

I need help with how to write a regex for getting the last 10 digits from the right side of the mobile Number
For examples:
Input is: 919345678901
output is: 9345678901
input2 is: 09934567892
output is: 9934567892
PL/SQL means Oracle; in that case, you don't need slow regular expressions as fast substr function does the job nicely:
Sample data:
SQL> with test (col) as
2 (select '919345678901' from dual union all
3 select '09934567892' from dual
4 )
Query begins here:
5 select col,
6 substr(col, -10) result
7 from test;
COL RESULT
------------ ----------------------------------------
919345678901 9345678901
09934567892 9934567892
SQL>
regexp_replace(target,'^\d*(\d{10})$', '\1')

How to get first string after character Oracle SQL

I'm trying to get first string after a character.
Example is like
ABCDEF||GHJ||WERT
I need only
GHJ
I tried to use REGEXP but i couldnt do it.
Can anyone help me with please?
Thank you
Somewhat simpler:
SQL> select regexp_substr('ABCDEF||GHJ||WERT', '\w+', 1, 2) result from dual;
^
RES |
--- give me the 2nd "word"
GHJ
SQL>
which reads as: give me the 2nd word out of that string. Won't work properly if GHJ consists of several words (but that's not what your example suggests).
Something like I interpret with a separator in place, In this case it is || or | example is with oracle database
-- pattern -- > [^] represents non-matching character and + for says one or more character followed by ||
-- 3rd parameter --> starting position
-- 4th parameter --> nth occurrence
WITH tbl(str) AS
(SELECT 'ABCDEF||GHJ||WERT' str FROM dual)
SELECT regexp_substr(str
,'[^||]+'
,1
,2) output
FROM tbl;
I think the most general solution is:
WITH tbl(str) AS (
SELECT 'ABCDEF||GHJ||WERT' str FROM dual UNION ALL
SELECT 'ABC|DEF||GHJ||WERT' str FROM dual UNION ALL
SELECT 'ABClDEF||GHJ||WERT' str FROM dual
)
SELECT regexp_replace(str, '^.*\|\|(.*)\|\|.*', '\1')
FROM tbl;
Note that this works even if the individual elements contain punctuation or a single vertical bar -- which the other solutions do not. Here is a comparison.
Presumably, the double vertical bar is being used for maximum flexibility.
You should use regexp_substr function
select regexp_substr('ABCDEF||GHJ||WERT ', '\|{2}([^|]+)', 1, 1, 'i', 1) str
from dual;
STR
---
GHJ

Conditional regexp_replace Oracle / PLSQL

I'm trying to do a conditional replace within one regexp_replace statement.
For example, if I have the string, 'Dog Cat Donkey', I would like to be able to replace 'Dog' with 'BigDog', 'Cat' with 'SmallCat' and 'Donkey' with 'MediumDonkey' to get the following:
'BigDog SmallCat MediumDonkey'
I can do it where all are prefixed with the word Big but can't seem to make it replace conditionally.
I currently have this
select regexp_replace('Dog Cat Donkey', '(Cat)|(Dog)|(Donkey)', ' Big\1\2\3')
from dual
but of course this only returns 'BigDog BigCat BigDonkey'.
I'm aware this isn't the best way of doing this but is it possible?
Have you considered just doing multiple replace()s?
select replace(replace(replace(str, 'Dog', 'BigDog'), 'Cat', 'SmallCat'), 'Donkey', 'MediumDonkey')
I get that regexp_replace() is really powerful. And it might be able to do this. But I'm not sure that's a better solution in terms of expressing what you are doing.
Query -
select listagg(final_str,' ') within group (order by sort_str) as output from (
SELECT
CASE LST
WHEN 'Dog' THEN 'BigDog'
WHEN 'Cat' THEN 'SmallCat'
WHEN 'Donkey' THEN 'MediumDonkey'
END AS final_str,
CASE LST
WHEN 'Dog' THEN 1
WHEN 'Cat' THEN 2
WHEN 'Donkey' THEN 3
END AS sort_str
from (
SELECT
trim(REGEXP_SUBSTR('Dog Cat Donkey', '(\S*)(\s*)', 1, LEVEL)) AS LST
FROM
DUAL
CONNECT BY
REGEXP_SUBSTR('Dog Cat Donkey', '(\S*)(\s*)', 1, LEVEL) IS NOT NULL
));
Output -
BigDog SmallCat MediumDonkey
For conditional replacement via REGEX_REPLACE?
Then currently you can do this by repeating it for each different replacement string.
But you could still use the | (OR) within the 1 capture group to change more than 1 word for the same replacement string.
And as Gordon Linoff pointed out.
You don't really need a REGEX_REPLACE when a normal REPLACE is sufficient to match a single word.
select regexp_replace(
regexp_replace(
regexp_replace( str,
'(Dog|Snoopy)', 'Big\1')
,'(Cat|Feline)', 'Small\1')
,'(Donkey|Ass)', 'Medium\1')
from (select 'You Ass, that is not a Dog, but a Cat on a Donkey.' as str from dual);
Returns:
You MediumAss, that is not a BigDog, but a SmallCat on a MediumDonkey.
Do note however that when using the pipe in a regex, that the order matters.
So if some words start the same then better put them in order of descending length.
Example:
select
regexp_replace(str, '(foo|foobar)', '[\1]') as foo_foobar,
regexp_replace(str, '(foobar|foo)', '[\1]') as foobar_foo
from (select 'foo foobar' as str from dual);
Returns:
FOO_FOOBAR FOOBAR_FOO
--------------- ---------------
[foo] [foo]bar [foo] [foobar]

extracting text from a column using regexp_substr

I have a table with a varchar column with data like this:
"<tasa>
<parametros>
<parametro>
<nombre>ea</nombre>
<valor>35</valor>
</parametro>
</parametros>
<valorTasa>3.15</valorTasa>
</tasa>"
I need to be able to extract the value between the valorTasa tags, but don't know how to use the function and can't access oracle documentation.
I'm trying something like
select regexp_substr(field, '<valorTasa>[0-9]{0-3}</valorTasa') from dual;
With no results.
Any help would be greatly appreciated
More simple way would be using extractvalue function to extract the value of the node.
-- sample of data
SQL> with t1(col) as(
2 select '<tasa>
3 <parametros>
4 <parametro>
5 <nombre>ea</nombre>
6 <valor>35</valor>
7 </parametro>
8 </parametros>
9 <valorTasa>3.15</valorTasa>
10 </tasa>'
11 from dual
12 )
13 select extractvalue(xmltype(col), '/tasa/valorTasa') as res
14 from t1
15 /
RES
-------
3.15
Actually REGEXP_REPLACE will work best for this. If you put a part of the search expression in parentheses you can refer to it in the third "replace-with" parameter - the first such expression is \1, the second is \2, and so on up to \9 (you can't do more than 9).
For your requirement, try this:
SELECT REGEXP_REPLACE(myXMLCol, '^.*<valorTasa>(.*)</valorTasa>.*$', '\1') FROM myTable
^^^^ ^^
The part in the parentheses above - (.*) maps to \1. The Oracle REGEXP_REPLACE docs explain this better than I can :)
SELECT regexp_replace(
regexp_substr(field, '<valorTasa>[0-9\.]+</valorTasa>'),
'<valorTasa>([0-9\.]+)</valorTasa>',
'\1')
from dual;
For multiline XML documents, as we have here, regexp_replace routine could be used but only with correct match_parameter = mn :
with t1(col) as(
select '<tasa>
<parametros>
<parametro>
<nombre>ea</nombre>
<valor>35</valor>
</parametro>
</parametros>
<valorTasa>3.15</valorTasa>
</tasa>'
from dual
)
select
REGEXP_REPLACE(col, '^.*<valorTasa>(.*)</valorTasa>.*$', '\1', 1, 0, 'mn') as res
from t1
/