Related
I am working with table data that contains strings with decimal and back-slash like below:
info
1/2.2.2
2/1.1.1
3/1.1.11
I need to use a regular expression to replace the data like below:
info
1/2.2
2/1.1
3/1.1
Don't use a (slow) regular expression, use simple (faster) string functions instead:
SELECT info,
CASE
WHEN INSTR(info, '.', 1, 2) > 0
THEN SUBSTR(info, 1, INSTR(info, '.', 1, 2) - 1)
ELSE info
END AS part
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (info) AS
SELECT '1/2.2.2' FROM DUAL UNION ALL
SELECT '2/1.1.1' FROM DUAL UNION ALL
SELECT '3/1.1.11' FROM DUAL UNION ALL
SELECT '3/1.1' FROM DUAL;
Outputs:
INFO
PART
1/2.2.2
1/2.2
2/1.1.1
2/1.1
3/1.1.11
3/1.1
3/1.1
3/1.1
If you want to update the table then:
UPDATE table_name
SET info = SUBSTR(info, 1, INSTR(info, '.', 1, 2) - 1)
WHERE INSTR(info, '.', 1, 2) > 0
fiddle
For the sake of argument, here's a solution using REGEXP_SUBSTR(). REGEXP_SUBSTR() returns NULL if the pattern is not found. Thanks to MT0 for the CTE so I didn't have to type it up :-)
WITH table_name(ID, info) AS (
SELECT 1, '1/2.2.2' FROM DUAL UNION ALL
SELECT 2, '2/1.1.1' FROM DUAL UNION ALL
SELECT 3, '3/1.1.11' FROM DUAL UNION ALL
SELECT 4, '3/1.1' FROM DUAL UNION ALL
SELECT 5, '4/4' FROM DUAL)
SELECT ID, REGEXP_SUBSTR(info, '\d/\d\.\d') DATA
from table_name;
ID DATA
---------- --------
1 1/2.2
2 2/1.1
3 3/1.1
4 3/1.1
5
5 rows selected.
I'm trying to count the words in a string using regex in Oracle 10g.
I've been trying this
select *
from books
where REGEXP_LIKE(title, '[ ]{2}');
so that its returning titles with at least 3 words in the title.
INSTR is also a viable option. By looking for the second occurrence of a space, that will indicate that the string has at least 3 words.
WITH
books
AS
(SELECT 'Tom Sawyer' title FROM DUAL
UNION ALL
SELECT 'A tale of two cities' FROM DUAL
UNION ALL
SELECT 'The Little Prince' FROM DUAL
UNION ALL
SELECT 'Don Quixote' FROM DUAL)
SELECT title
FROM books
WHERE instr(title, ' ', 1, 2) > 0;
If you do with to stick with regex, the regex expression below can be used to find books that have 3 or more words.
WITH
books
AS
(SELECT 'Tom Sawyer' title FROM DUAL
UNION ALL
SELECT 'A tale of two cities' FROM DUAL
UNION ALL
SELECT 'The Little Prince' FROM DUAL
UNION ALL
SELECT 'Don Quixote' FROM DUAL)
SELECT title
FROM books
WHERE REGEXP_LIKE (title, '(\S+\s){2,}');
(Thanks #Littlefoot for the books!)
REPLACE does the job (with some calculation).
SQL> with books as
2 (select 'Tom Sawyer' title from dual union all
3 select 'A tale of two cities' from dual union all
4 select 'The Little Prince' from dual union all
5 select 'Don Quixote' from dual
6 )
7 select title
8 from books
9 where length(title) - length(replace(title, ' ', '')) >= 2;
TITLE
--------------------
A tale of two cities
The Little Prince
SQL>
The below one is simple and easy to understand (works on 11g and later):
The below is just to create some sample data
create table books as
with tab as
(
select 'Tom Sawyer' title from dual
union all
select 'A tale of two cities' from dual
union all
select 'The Little Prince' from dual
union all
select 'The_Little_Prince' from dual
union all
select 'Don Quixote' from dual
union all
select null from dual
)
select title
from tab;
The below is your solution to get those titles that have at least 3 words in it
select title
from books
where regexp_count(title, '\w+') > 2
Output:
1. <0,0><120.96,2000><241.92,4000><362.88,INF>
2. <0,0><143.64,2000><241.92,4000><362.88,INF>
3. <0,0><125.5,2000><241.92,4000><362.88,INF>
4. <0,0><127.5,2000><241.92,4000><362.88,INF>
Above is the data set I have in Oracle 10g. I need output as below
1. 120.96
2. 143.64
3. 125.5
4. 125.5
the output I want is only before "comma" (120.96). I tried using REGEXP_SUBSTR but I could not get any output. It will be really helpful if someone could provide effective way to solve this
Here is one method that first parses out the second element and then gets the first number in it:
select regexp_substr(regexp_substr(x, '<[^>]*>', 1, 2), '[0-9.]+', 1, 1)
Another method just gets the third number in the string:
select regexp_substr(x, '[0-9.]+', 1, 3)
Here is an approach without using Regexp.
Find the index of second occurrence of '<'. Then find the second occurrence of ',' use those values in substring.
with
data as
(
select '<0,0><120.96,2000><241.92,4000><362.88,INF>' x from dual
UNION ALL
select '<0,0><143.64,2000><241.92,4000><362.88,INF>' x from dual
UNION ALL
select '<0,0><125.5,2000><241.92,4000><362.88,INF>' from dual
)
select substr(x, instr(x,'<',1,2)+1, instr(x,',',1,2)- instr(x,'<',1,2)-1)
from data
Approach Using Regexp:
Identify the 2nd occurence of numerical value followed by a comma
Then remove the trailing comma.
with
data as
(
select '<0,0><120.96,2000><241.92,4000><362.88,INF>' x from dual
UNION ALL
select '<0,0><143.64,2000><241.92,4000><362.88,INF>' x from dual
UNION ALL
select '<0,0><125.5,2000><241.92,4000><362.88,INF>' from dual
)
select
trim(TRAILING ',' FROM regexp_substr(x,'[0-9.]+,',1,2))
from data
This example uses regexp_substr to get the string contained within the 2nd occurance of a less than sign and a comma:
SQL> with tbl(id, str) as (
select 1, '<0,0><120.96,2000><241.92,4000><362.88,INF>' from dual union
select 2, '<0,0><143.64,2000><241.92,4000><362.88,INF>' from dual union
select 3, '<0,0><125.5,2000><241.92,4000><362.88,INF>' from dual union
select 4, '<0,0><127.5,2000><241.92,4000><362.88,INF>' from dual
)
select id,
regexp_substr(str, '<(.*?),', 1, 2, null, 1) value
from tbl;
ID VALUE
---------- -------------------------------------------
1 120.96
2 143.64
3 125.5
4 127.5
EDIT: I realized the OP specified 10g and the regexp_substr example I gave used the 6th argument (subgroup) which was added in 11g. Here is an example using regexp_replace instead which should work with 10g:
SQL> with tbl(id, str) as (
select 1, '<0,0><120.96,2000><241.92,4000><362.88,INF>' from dual union
select 2, '<0,0><143.64,2000><241.92,4000><362.88,INF>' from dual union
select 3, '<0,0><125.5,2000><241.92,4000><362.88,INF>' from dual union
select 4, '<0,0><127.5,2000><241.92,4000><362.88,INF>' from dual
)
select id,
regexp_replace(str, '^(.*?)><(.*?),.*$', '\2') value
from tbl;
ID VALUE
---------- ----------
1 120.96
2 143.64
3 125.5
4 127.5
SQL>
I have a field as name in a table with names inserted without spaces. Eg: "MarkJones".
Now I want to create a space between the first and lastname of a person within the same column to be displayed as "Mark Jones" using Oracle functions.
I have tried this query
SELECT instr('MarkJones', '%||Upper(*)||%') AS substr1,
SUBSTR('MarkJones', instr('MarkJones', '%lower(*)upper(*)%')) AS substr2,
substr1||' '||substr2
FROM dual
;
However, this query is not working. I want to try it using oracle functions including translate, substr and instr, but no regular expressions.
This approach works for the simple example given, but fails if the name has more than 2 uppercase letters in it. If this is coursework as expected, maybe the requirements are not too difficult for the names to parse as we all know that is fraught with heartache and you can never account for 100% of names from all nationalities.
Anyway my approach was to move through the string looking for uppercase letters and if found replace them with a space followed by the letter. I used the ASCII function to test their ascii value to see if they were an uppercase character. The CONNECT BY construct (needed to loop through each character of the string) returns each character in its own row so LISTAGG() was employed to reassemble back into a string and ltrim to remove the leading space.
I suspect if this is coursework it may be using some features you should not be using yet. At least you should get out of this the importance of receiving and/or giving complete specifications!
SQL> with tbl(name) as (
select 'MarkJones' from dual
)
select ltrim(listagg(case
when ascii(substr(name, level, 1)) >= 65 AND
ascii(substr(name, level, 1)) <= 90 THEN
' ' || substr(name, level, 1)
else substr(name, level, 1)
end, '')
within group (order by level)) fixed
from tbl
connect by level <= length(name);
FIXED
------------------------------------
Mark Jones
When you are ready, here's the regexp_replace version anyway :-)
Find and "remember" the 2nd occurrence of an uppercase character then replace it with a space and the "remembered" uppercase character.
SQL> with tbl(name) as (
select 'MarkJones' from dual
)
select regexp_replace(name, '([A-Z])', ' \1', 1, 2) fixed
from tbl;
FIXED
----------
Mark Jones
Not sure we should go against #Alex Poole advice, but it looks like an homework assignment.
So my idea is to point the second Upper Case. Its doable if you create a set of the upper cases, on which you valuate the position in input string iStr. Then if you're allowed to use length, you can use this position to build firstName too:
SELECT substr(iStr, 1, length(iStr)-length(substr(iStr, instr(iStr, u)))) firstName
, substr(iStr, instr(iStr, u)) lastName
, substr(iStr, 1, length(iStr)-length(substr(iStr, instr(iStr, u)))) ||' '||
substr(iStr, instr(iStr, u)) BINGO
FROM ( select 'MarkJones' iStr from dual
union all select 'SomeOtherNames' from dual -- 2 u-cases gives 2 different results
union all select 'SomeOtherOols' from dual -- only one result
union all select 'AndJim' from dual
union all select 'JohnLenon' from dual
union all select 'LemingWay' from dual
),
( select 'A' U from dual
union all select 'B' from dual
union all select 'C' from dual
union all select 'D' from dual
union all select 'E' from dual
union all select 'F' from dual
union all select 'G' from dual
union all select 'H' from dual
union all select 'I' from dual
union all select 'J' from dual
union all select 'K' from dual
union all select 'L' from dual
union all select 'M' from dual
union all select 'N' from dual
union all select 'O' from dual
union all select 'P' from dual
union all select 'Q' from dual
union all select 'R' from dual
union all select 'S' from dual
union all select 'T' from dual
union all select 'U' from dual
union all select 'V' from dual
union all select 'W' from dual
union all select 'X' from dual
union all select 'Y' from dual
union all select 'Z' from dual
) upper_cases
where instr(iStr, U) > 1
;
I am working on below query, I am expected to select exact 7 or 10 digit values columns using regular expression, I have used express in regexp_like() function of oracle, but its not working, please help
Query :
select * from
(select '1234567CELL' "a" from dual
union
select '123CaLLAsasd12' "a" from dual
union
select 'as9960488188CELLas12' "a" from dual
union
select '1234567' "a" from dual
union
select '9960488188' "a" from dual
union
select 'asdCELLqw' "a" from dual) b
where b."a" like '%CELL%' and regexp_like(b."a",'^(\d{7}|\d{10})$');
Expected output
"1234567"
"9960488188"
as above two rows, please check
^ and $ match the start and end of a string and the value cannot contain the string CELL and be solely a 7- or 10-digit number. Instead you could use the regular expression (^|\D)(\d{7}|\d{10})($|\D) which will match either the start of the string or a not digit character (^|\D) then either 7- or 10- digits and then either the end of the string or a non digit character ($|\D).
Like this:
WITH data ( a ) AS (
select '1234567CELL' from dual union
select '123CaLLAsasd12' from dual union
select 'as9960488188CELLas12' from dual union
select '1234567' from dual union
select '9960488188' from dual union
select 'asdCELLqw' from dual
)
SELECT a,
REGEXP_SUBSTR( a, '(^|\D)(\d{7}|\d{10})($|\D)', 1, 1, NULL, 2 ) AS val
FROM data
WHERE a LIKE '%CELL%'
AND REGEXP_LIKE( a, '(^|\D)(\d{7}|\d{10})($|\D)');
Output:
A VAL
-------------------- ----------
1234567CELL 1234567
as9960488188CELLas12 9960488188
You may just use
where regexp_like(b."a",'^([[:digit:]]{7}|[[:digit:]]{10})$')
Since the pattern is anchored (^ matches the start of the string and $ matches the end of the string) there can't be CELL inside the entries you fetch, and you can remove where b."a" like '%CELL%' from the query.