Split by uppercase Oracle - sql

I am loooking for a regex expression or something that from this :
------------------------
| id | prop_name |
------------------------
| 1 | isThisAnExample |
------------------------
To this :
-----------------------------
| id | prop_name |
-----------------------------
| 1 | Is This An Example |
-----------------------------
Of course it would be cool if the first character is uppercase and also if the other words start with lowercase. But only spliting them also will be okay.

Maybe this is the regexp you are looking for
"Insert a blank between each lower case character followed by an upper case character":
select regexp_replace('IsThisAnExample', '([[:lower:]])([[:upper:]])', '\1 \2') from dual
First character can simply replaced by an upper case letter by
select upper(substr('isThisAn Example', 1,1))||substr('isThisAn Example', 2) from dual;
So, first replace the first character and regexp_replace for the result:
select regexp_replace(upper(substr('isThisAn Example', 1,1))||substr('isThisAn Example', 2), '([[:lower:]])([[:upper:]])', '\1 \2') from dual;
If only the first character of your sentence should be an upper case letter, then try:
select upper(substr(regexp_replace('IsThisAnExample', '([[:lower:]])([[:upper:]])', '\1 \2'),1,1))||
lower(substr(regexp_replace('IsThisAnExample', '([[:lower:]])([[:upper:]])', '\1 \2'),2))
from dual

Better use regex, but anyway:
SELECT listagg(splitted, '') within GROUP (ORDER BY lvl) FROM(
SELECT LEVEL lvl, CASE WHEN SUBSTR(your_string, LEVEL, 1) =
UPPER(SUBSTR(your_string, LEVEL, 1))
THEN ' ' || SUBSTR(your_string, LEVEL, 1) ELSE
SUBSTR(your_string, LEVEL, 1) END splitted
FROM (SELECT 'isThisAnExample' your_string FROM dual)
CONNECT BY LEVEL <= LENGTH(your_string) );

Similar to Frank's solution, but simpler (reducing the use of regular expressions as much as possible):
with
input ( str ) as (
select 'isThisAnExample' from dual
)
select upper(substr(str, 1, 1)) ||
lower(regexp_replace(substr(str, 2), '(^|[[:lower:]])([[:upper:]])', '\1 \2'))
as modified_str
from input;
MODIFIED_STR
------------------
Is this an example
1 row selected.

Related

Oracle query to replace same character with different characters based on position

I have a string in Oracle DB in the format 'a|b|c' , '|' being the separator between characters. Want to write an SQL query to transform it into a string in the format 'a,b&c'. First occurrence of '|' to ',' 2nd occurrence to '&'.
If suppose the string comes in the format 'a|b' then output should be 'a&b'.
I'm using multiple regex_replace queries to achieve this right now.
select REGEXP_REPLACE ('a|b|c', '[|]', ',', 1, 1)
from dual
Is there any other solution using one single query?
Nested replaces (see line #6):
SQL> with test (col) as
2 (select 'a|b|c' from dual union all
3 select 'a|b' from dual
4 )
5 select col,
6 regexp_replace(regexp_replace(col, '\|', ',', 1, 1), '\|', '&', 2, 1) result
7 from test;
COL RESULT
----- --------------------
a|b|c a,b&c
a|b a,b
SQL>
If you want to replace the last | in the list with & and all the preceding |s with , then you can use:
SELECT value,
REPLACE(
REGEXP_REPLACE( value, '\|([^|]*)$', '&\1' ),
'|',
','
) AS replaced
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (value) AS
SELECT 'A|B|C|D' FROM DUAL UNION ALL
SELECT 'A|B|C' FROM DUAL UNION ALL
SELECT 'A|B' FROM DUAL UNION ALL
SELECT 'A' FROM DUAL;
Outputs:
VALUE
REPLACED
A|B|C|D
A,B,C&D
A|B|C
A,B&C
A|B
A&B
A
A
fiddle

REGEXP to validate a specific number

How can I search for a specific number in an array using REGEXP?
I have an array and need to verify if it has a specific number.
Ex: [5,2,1,4,6,19] and I am looking for number 1, but just the number 1 and not any number that contain the digit 1.
I had to do this:
case when REGEXP_INSTR(JSON_QUERY(MY_JSON_COLUMN,'$.path') , '[[]{1}[1][,]')<>0
or REGEXP_INSTR(JSON_QUERY(MY_JSON_COLUMN,'$.path') , '[,]{1}[1][,]{1}')<>0
or REGEXP_INSTR(JSON_QUERY(MY_JSON_COLUMN,'$.path') , '[,]{1}[1][]]')<>0
or REGEXP_INSTR(JSON_QUERY(MY_JSON_COLUMN,'$.path') , '[[]{1}[1][]]') <>0
then 'DIGIT_ONE' else 'NO_DIGIT_ONE'
end
Is there anything simpler?
You can use
(^|\D)1(\D|$)
This will seach for 1 not enclosed with other digits.
See this regex demo.
Details
(^|\D) - start of string or non-digit
1 - a 1 char
(\D|$) - non-digit or end of string.
Do NOT use regular expressions, use a proper JSON parser and then filter for the number you want:
SELECT my_json_column,
CASE
WHEN JSON_EXISTS( my_json_column, '$?(#.path[*] == 1)' )
THEN 'DIGIT ONE'
ELSE 'NO DIGIT ONE'
END AS has_one
FROM table_name;
or (if you are using Oracle 12.1 and cannot use path filter expressions with JSON_EXISTS, which is only available from Oracle 12.2):
SELECT my_json_column,
CASE
WHEN EXISTS(
SELECT 'X'
FROM JSON_TABLE(
t.my_json_column,
'$.path[*]'
COLUMNS (
value NUMBER PATH '$'
)
)
WHERE value = 1
)
THEN 'DIGIT ONE'
ELSE 'NO DIGIT ONE'
END
FROM table_name t;
Which, for the sample data:
CREATE TABLE table_name (
my_json_column CHECK ( my_json_column IS JSON )
) AS
SELECT '{"path":[5,2,1,4,6,19],"not_this_path":[1,2,3,4,5]}' FROM DUAL UNION ALL
SELECT '{"path":[5,2,4,6,19],"not_this_path":[1,2,3,4,5]}' FROM DUAL UNION ALL
SELECT '{"path":[11],"not_this_path":[1]}' FROM DUAL UNION ALL
SELECT '{"path":[2],"not_this_path":[1]}' FROM DUAL UNION ALL
SELECT '{"path":[1,11]}' FROM DUAL;
Both output:
MY_JSON_COLUMN | HAS_ONE
:-------------------------------------------------- | :-----------
{"path":[5,2,1,4,6,19],"not_this_path":[1,2,3,4,5]} | DIGIT ONE
{"path":[5,2,4,6,19],"not_this_path":[1,2,3,4,5]} | NO DIGIT ONE
{"path":[11],"not_this_path":[1]} | NO DIGIT ONE
{"path":[2],"not_this_path":[1]} | NO DIGIT ONE
{"path":[1,11]} | DIGIT ONE
db<>fiddle here
Alternatively, with a little bit more typing (a little bit? Am I kidding?!), splitting the string into rows and comparing values to the search string:
SQL> with test (col) as
2 (select '[5,2,1,4,6,19]' from dual)
3 select t.col,
4 case when '&par_search_string' in
5 (select regexp_substr(substr(col, 2, length(col) - 1), '[^,]+', 1, level) val
6 from test
7 connect by level <= regexp_count(col, ',') + 1
8 )
9 then 'Search string exists'
10 else 'Search string does not exist'
11 end result
12 from test t;
Enter value for par_search_string: 1
COL RESULT
-------------- ----------------------------
[5,2,1,4,6,19] Search string exists
SQL> /
Enter value for par_search_string: 24
COL RESULT
-------------- ----------------------------
[5,2,1,4,6,19] Search string does not exist
SQL>

how to get 8 characters in a string after joining two words in oracle sql

i need to get first 8 characters after replacing whitespaces of a two string example "united states of america" by find and replace removed whitespaces "unitedstatesofamerica" but i need string upto length of 8 after removing whitespaces ie "unitedst" pls help me
I think you just want substr():
select substr(replace(col, ' ', ''), 1, 8)
One option would be using [[:space:]] POSIX within REGEXP_REPLACE() function in order to remove all whitespace characters including non-printable ones such as
SELECT SUBSTR( REGEXP_REPLACE(col,'[[:space:]]'), 1, 8) AS col
FROM t -- your original table
Demo
If you need to remove all whitespaces (spaces, tabs, line breaks) then you want to use a regular expression to replace the whitespaces and then you can use SUBSTR to find the first 8 characters:
SELECT SUBSTR(REGEXP_REPLACE(col, '\s+'), 1, 8)
FROM table_name
Which, for the test data:
CREATE TABLE table_name ( col ) AS
SELECT 'United States of America' FROM DUAL UNION ALL
SELECT 'ABCDEFGHIJKLM' FROM DUAL UNION ALL
SELECT 'A B' || CHR(9) || 'C' || CHR(13) || CHR(10) || 'D E F G H I J K L M' FROM DUAL;
Outputs:
| SUBSTR(REGEXP_REPLACE(COL,'\S+'),1,8) |
| :------------------------------------ |
| UnitedSt |
| ABCDEFGH |
| ABCDEFGH |
db<>fiddle here

How to get number between special character in oracle

Can you help to get below output in oracle
File_20170902_Name.txt
File200_Name_20170902_1.txt
File400_20170902_Name_1.txt
File1_name_20170902.txt
I am expecting output like
20170902
20170902
20170902
20170902
Thanks in advance!!
Assuming that all the 8 digit numbers in your filenames are dates and are preceded by a _ and followed by an _ or .txt, you may use
select REGEXP_SUBSTR(files,'_(\d{8})(_|.txt)',1,1,NULL,1) as dt FROM t;
Demo
But some time number character will change like 6 (YYMMDD) character
This will match a sequence of 6 to 8 characters between _ or _ and .txt
REGEXP_SUBSTR(files,'_((\d{6,8}))(_|)',1,1,NULL,1)
Demo2
But, This isn't a comprehensive regex to match dates. i.e it could match digits like 20189999 or 180000 if they are part of filename. if you want to detect only dates, then you may have to combine them with methods specified here: Valid Date Checks in Oracle
Try this demo: http://sqlfiddle.com/#!4/c361c/4
select
regexp_replace(str,'.*(\d{8}).*','\1') as x
from table1
| X |
|----------|
| 20170902 |
| 20170902 |
| 20170902 |
| 20170902 |
Try this
create table tst (x varchar2(30));
insert into tst values ('File_20170902_Name.txt');
insert into tst values ('File200_Name_20170902_1.txt');
insert into tst values ('File400_20170902_Name_1.txt');
insert into tst values ('File1_name_20170902.txt');
Select x,
case
when substr(x, REGEXP_INSTR(x, '[^a-z|A-Z|0-9]') + 1, 1) between chr(48) and chr(57) Then
substr(x, REGEXP_INSTR(x, '[^a-z|A-Z|0-9]') + 1, REGEXP_INSTR(x, '[^a-z|A-Z|0-9]', 1, 2) - REGEXP_INSTR(x, '[^a-z|A-Z|0-9]') - 1)
else substr(x, REGEXP_INSTR(x, '[^a-z|A-Z|0-9]', 1, 2) + 1, REGEXP_INSTR(x, '[^a-z|A-Z|0-9]', 1, 3) - REGEXP_INSTR(x, '[^a-z|A-Z|0-9]', 1, 2) - 1)
end as t
From tst
Note: this query wont support if the number start after more than 2 special character like File_name_test_20170902.txt
The following both work about the same - the use a regular expression to make the basic selection, then make use of either a second call to REGEXP_SUBSTR or use "normal" string functions to get rid of the delimiters. I prefer the nested calls to REGEXP_SUBSTR over the use of TRANSLATE or REPLACE but you can take your pick:
Nested calls to REGEXP_SUBSTR:
WITH cteFiles AS (SELECT 'File_20170902_Name.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File200_Name_20170902_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File400_20170902_Name_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File1_name_20170902.txt' AS FILENAME FROM DUAL)
SELECT FILENAME, REGEXP_SUBSTR(REGEXP_SUBSTR(FILENAME, '_[0-9]+[_.]'), '[^_.]+') AS FINAL_NUMS
FROM cteFiles;
Using REPLACE:
WITH cteFiles AS (SELECT 'File_20170902_Name.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File200_Name_20170902_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File400_20170902_Name_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File1_name_20170902.txt' AS FILENAME FROM DUAL)
SELECT FILENAME, REPLACE(REPLACE(REGEXP_SUBSTR(FILENAME, '_[0-9]+[_.]'), '_', NULL), '.', NULL) AS FINAL_NUMS
FROM cteFiles;
Using TRANSLATE:
WITH cteFiles AS (SELECT 'File_20170902_Name.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File200_Name_20170902_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File400_20170902_Name_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File1_name_20170902.txt' AS FILENAME FROM DUAL)
SELECT FILENAME, TRANSLATE(REGEXP_SUBSTR(FILENAME, '_[0-9]+[_.]'), '0123456789_.', '0123456789') AS FINAL_NUMS
FROM cteFiles;
SQLFiddle here
Best of luck.

regexp_substr with LIKE as search condition

Thank you mathguy for your suggestion and assistance. The example you provided is a near perfect description of the issue. That being said I've used and edited your text to help describe this issue:
I receive a string that contains comma delimited digits in the form of 18656, 16380, 16424 (call this param1). The string only contains commas and digits.
In mytable I have a column named t with values such as 18656.01.02, 10.02.02, 16380.02.03, 16424.05.66, 16424.55.23.14.
I want to select the all rows that match all of the comma-separated digits in param1; where the first numeric component in column t is like 18656, 16380, 16424. Is there a way to use regexp_substr in this case.
Where param1 = 18656, 16380, 16424
the following works:
select * from mytable where t.mycolumn IN
(
(SELECT regexp_substr(:param1,'[^,]+', 1, level) as NUMLIST
FROM DUAL
CONNECT BY regexp_substr(:param1, '[^,]+', 1, level) IS NOT NULL)
);
How to use wildcard if data I seek from t.mycolumn = 18656.00.01, 16380.09.34, 16424.023.8
Can LIKE be used as search criteria? If possible please provide example.
Obviously, the following will not work but I am hoping to find a solution.
select * from mytable where t.mycolumn LIKE
(
(SELECT regexp_substr(:param1||'%','[^,]+', 1, level) as NUMLIST
FROM DUAL
CONNECT BY regexp_substr(:param1||'%', '[^,]+', 1, level) IS NOT NULL)
);
Assumptions:
There is a table named mytable with a column named t which
contains values as follows:
SELECT * FROM mytable;
T |
---------------|
18656.01.02 |
10.02.02 |
16380.02.03 |
16424.05.66 |
16424.55.23.14 |
There is a string received as a parameter, that contains comma delimited digits in the form of 18656, 16380, 16424. The string only contains commas and digits. This string is parsed into indyvidual rows with a help of a query that looks similar to the folowing one:
SELECT regexp_substr(param1,'[^,]+', 1, level) as NUMLIST
FROM (
select '18656,16380,16424' as param1 FROM DUAL
)
CONNECT BY regexp_substr(param1, '[^,]+', 1, level) IS NOT NULL
;
NUMLIST |
--------|
18656 |
16380 |
16424 |
Requirement
Can LIKE be used as search criteria? If possible please provide
example.
LIKE keyword is used below as a condition in JOIN ... ON clause:
SELECT * FROM mytable
WHERE t IN (
SELECT t
FROM mytable m
JOIN (
SELECT regexp_substr(param1,'[^,]+', 1, level) as NUMLIST
FROM (
select '18656,16380,16424' as param1 FROM DUAL
)
CONNECT BY regexp_substr(param1, '[^,]+', 1, level) IS NOT NULL
) x
ON m.t LIKE '%' || x.NUMLIST || '%'
)
T |
---------------|
18656.01.02 |
16380.02.03 |
16424.05.66 |
16424.55.23.14 |