Remove all dots except its last occurrence - sql

I need regex to remove dots from a number, but not the last one.
What I'd like to do:
100.000.10 -> 100000.10
I tried with:
SELECT REGEXP_REPLACE ('100.100.10', '\.(?![^.]+$)|[^0-9.]','') FROM dual;
But it return 100.100.10

You do not need (slow) regular expression and can use (much faster) simple string functions:
SELECT REPLACE(SUBSTR(value, 1, INSTR(value, '.', -1) - 1), '.')
|| SUBSTR(value, INSTR(value, '.', -1)) AS updated_value
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (value) AS
SELECT '100.000.10' FROM DUAL;
Outputs:
UPDATED_VALUE
100000.10
fiddle

Related

How to Select a substring in Oracle SQL from and up to some specific characters?

i am using oracle sql. i would like to substr starting from characters XY0 and include 2 or 3 more characters until '-' sign in the string
These characters may be anywhere in the string.
Original
column_value
1st Row - Error due to XY0066- Does not fit -Not suitable
2nd Row -Error due to specific XY0089- Will not match
3rd Row -Not in good cond XY0215- Special type error
Extraction should be
result
XY0066
XY0089
XY0215
How can I do this?
You can use:
SELECT id,
SUBSTR(value, start_pos, end_pos - start_pos) AS code
FROM (
SELECT id,
value,
INSTR(value, 'XY') AS start_pos,
INSTR(value, '-', INSTR(value, 'XY') + 2) AS end_pos
FROM table_name
);
or
SELECT id,
SUBSTR(
value,
INSTR(value, 'XY'),
INSTR(value, '-', INSTR(value, 'XY') + 2) - INSTR(value, 'XY')
) AS code
FROM table_name;
or using regular expressions, which is shorter to type but will run much slower:
SELECT id,
REGEXP_SUBSTR(value, 'XY[^-]*') AS code
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (id, value) AS
SELECT 1, 'Error due to XY0066- Does not fit -Not suitable' FROM DUAL UNION ALL
SELECT 2, 'Error due to specific XY0089- Will not match' FROM DUAL UNION ALL
SELECT 3, 'Not in good cond XY0215- Special type error' FROM DUAL;
All output:
ID
CODE
1
XY0066
2
XY0089
3
XY0215
fiddle

Oracle: instr+substr instead of regexp_substr

I got this query from another post I made which uses REGEXP_SUBSTR() to pull out specific information from a string in oracle. It works good but only for small sets of data. When it comes to tables that have 300,000+ records, it is very slow and I was doing some reading that instr + substr might be faster. The example query is:
SELECT REGEXP_SUBSTR(value, '(^|\|)\s*24=\s*(.*?)\s*(\||$)', 1, 1, NULL, 2) AS "24",
REGEXP_SUBSTR(value, '(^|\|)\s*35=\s*(.*?)\s*(\||$)', 1, 1, NULL, 2) AS "35",
REGEXP_SUBSTR(value, '(^|\|)\s*47A=\s*(.*?)\s*(\||$)', 1, 1, NULL, 2) AS "47A",
REGEXP_SUBSTR(value, '(^|\|)\s*98A=\s*(.*?)\s*(\||$)', 1, 1, NULL, 2) AS "98A"
FROM table_name
Table example:
CREATE TABLE table_name (value ) AS
SELECT '35= 88234.00 | 47A= Shawn | 98A= This is a comment |' FROM DUAL UNION ALL
SELECT '24= 123.00 | 98A= This is a comment | 47A= Derick |' FROM DUAL
Output of query would be:
24
35
47A
98A
88234.00
Shawn
This is a comment
123.00
Derick
This is a comment
Can someone give me an example of how this same query would look if I was doing instr+substr instead?
Thank you.
SELECT CASE
WHEN start_24 > 0
THEN TRIM(
SUBSTR(
value,
start_24 + 5,
INSTR(value, '|', start_24 + 5) - (start_24+5)
)
)
END AS "24",
CASE
WHEN start_35 > 0
THEN TRIM(
SUBSTR(
value,
start_35 + 5,
INSTR(value, '|', start_35 + 5) - (start_35+5)
)
)
END AS "35",
CASE
WHEN start_47a > 0
THEN TRIM(
SUBSTR(
value,
start_47a + 6,
INSTR(value, '|', start_47a + 6) - (start_47a+6)
)
)
END AS "47A",
CASE
WHEN start_98a > 0
THEN TRIM(
SUBSTR(
value,
start_98a + 6,
INSTR(value, '|', start_98a + 6) - (start_98a+6)
)
)
END AS "98A"
FROM (
SELECT value,
INSTR(value, '| 24=') AS start_24,
INSTR(value, '| 35=') AS start_35,
INSTR(value, '| 47A=') AS start_47a,
INSTR(value, '| 98A=') AS start_98a
FROM (
SELECT '| ' || value AS value FROM table_name
)
);
Which, for your sample data, outputs:
24
35
47A
98A
88234.00
Shawn
This is a comment
123.00
Derick
This is a comment
db<>fiddle here
Given the data in your example it seems you could also use a procedural approach for your data extraction, but I'm sceptical if this could be faster.
The following function get24 for example extracts the columns "24" just using INSTR and SUBSTR.
CREATE OR REPLACE FUNCTION get24(value IN VARCHAR2) RETURN VARCHAR2
IS
i PLS_INTEGER;
s VARCHAR2(32767);
BEGIN
i := INSTR(value, '24= ');
IF (i <> 1) THEN
RETURN NULL;
END IF;
s := SUBSTR(value, i + 4);
i := INSTR(s, ' | ');
IF (i = 0) THEN
RETURN NULL;
END IF;
RETURN SUBSTR(s, 1, i - 1);
END;
/
SELECT get24(value) "24" FROM table_name;
You could then also try using a pipelined function and do all the data extraction within the pipelined function.

Extract the second word from a string in ODI Expression

This two syntaxes allow to get the scond word from a string in oracle
SELECT REGEXP_SUBSTR('Hello this is an example', '\s+(\w+)\s') AS syntax1,
SUBSTR('Hello this is an example',
INSTR('Hello this is an example', ' ', 1, 1) + 1,
INSTR('Hello this is an example', ' ', 1, 2)
- INSTR('Hello this is an example', ' ', 1)
) AS syntax2
FROM dual;
Result:
syntax1 syntax2
------- -------
this this
I'm working in ODI (oracle data integration), this two syntaxes doesn't work in ODI:
For ODI, the regexp is not valid and INSTR function accepts only 2 parameters
Can you suggest me a solution that can work in ODI?
Thank you.
I think it should support ' [[:alpha:]]+ '
Then, you can apply SUBSTR() function twice :
WITH t2(str) AS
(
SELECT SUBSTR( TRIM( str ), INSTR( TRIM( str ), ' ') + 1, LENGTH( TRIM(str) ) )
FROM t --> original table
)
SELECT SUBSTR( str, 1, INSTR(str, ' ') - 1 ) AS extracted_string
FROM t2
extracted_string
----------------
this
If the version of installed ODI is 12+, then you can also use REGEXP_REPLACE() as below one :
SELECT REGEXP_REPLACE(str, '(\w+)\s(\w+)( .*)', '\2' ) AS extracted_string
FROM t
Demo
I finaly used this expression:
SELECT
SUBSTR (
SUBSTR ('one two three four',
INSTR ('one two three four', ' ') + 1,
999999),
0,
INSTR (
SUBSTR ('one two three four',
INSTR ('one two three four', ' ') + 1,
999999),
' ')
- 1)
FROM DUAL

select regexp_replace('aaa_bbb', '(_.)', upper('\1')) from dual

Using Oracle 11g
select regexp_replace('aaa_bbb', '(_.)', upper('\1')) from dual;
I want 'aaa_Bbb'.
But, it returns 'aaa_bbb'.
Why can't replace?
Upper execute earlier Regexp
select regexp_replace('aaa_bbb', '(_.)', upper(regexp_substr('aaa_bbb', '(_.)'))) from dual
The problem with
select regexp_replace('aaa_bbb', '(_.)', upper('\1')) from dual;
is that upper is executed before regexp_replace, effectively making it:
select regexp_replace('aaa_bbb', '(_.)', '\1') from dual;
So you need a different approach.
See the answer to oracle regexp replace uppercase replacement string
If it doesn't have to be regular expressions approach, then substr + instr + initcap might help.
SQL> with test (col) as
2 (select 'aaa_bbb' from dual)
3 select substr(col, 1, instr(col, '_')) || initcap(substr(col, instr(col, '_') + 1)) result
4 from test;
RESULT
-------
aaa_Bbb
SQL>
I don't think there's a direct method to convert by using regexp_replace but it's possible by regexp_substr in such a way :
with t(str) as
(
select 'aaa_bbb' from dual
)
select concat( regexp_substr(str, '.*[_^]'), initcap( regexp_substr(str, '[^_]+$') ) )
as "Formatted String"
from t;
Formatted String
----------------
aaa_Bbb
Demo

Oracle REGEXP_LIKE to use lookaround or AND ignoring the order

I am trying to find a match with a given list of search parameters appearing anywhere in the given string. The search parameters can be OR or AND. REGEXP_LIKE with REPLACE works fine with OR (|) but not able to do for AND. Here is an example of OR:
select 'match' from dual WHERE REGEXP_LIKE('BCR081', REPLACE ('BCR;081', ';', '|')); --works
select 'match' from dual WHERE REGEXP_LIKE('BCR081', '(' || REPLACE ('BCR;081', ';', ').*?(') || ')');
-- Works when they are in order but order shouldn't matter.
select 'match' from dual WHERE REGEXP_LIKE('BCR081', '(' || REPLACE ('081;BCR', ';', ').*?(') || ')'); --I need this to work.
Is there something equivalent to
select 'match' from dual WHERE REGEXP_LIKE('BCR081', REPLACE ('BCR;081', ';', '&'));
Any help is greatly appreciated. I tried (look ahead?):
select 'match' from dual WHERE REGEXP_LIKE('BCR081','(?=' || REPLACE ('081;BCR', ';', ')(?=') || ')');
Note: The above is an example only, we can have anywhere from 1-20 search parameters. Also can't use the contains clause as it will throw too many results error.
We can tokenise the search string and look for one by one, by virtually generating rows.
with my_data as
(
select 'BCR081' as str , 'BCR;081' as pattern from dual
),
pattern_table as
(
select str, regexp_substr(pattern,'[^;]+',1,level) as pattern
from my_data
connect by level <= regexp_count(pattern,';') + 1
)
SELECT DECODE(
COUNT(DECODE(
INSTR(a.str,b.pattern),
0,
null,
1)
),
0,
'no match',
'match'
) as result
FROM my_data a, pattern_table b
WHERE a.str = b.str
GROUP BY a.str;