regexp_substr with LIKE as search condition - sql

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 |

Related

SQL: using regexp_substr ot regexp_extract, looking for the regex pattern that will only return the string between one character and a space

The row I am trying to parse from is a series of string values separated only by spaces. Sample below:
TX:123 SP:XapZNsyeS INST:456123
I need to use either regexp_substr or regexp_extract to return only values for the string that appears after "TX:" or "SP:", etc. So essentially an expression that only captures the string after a string (e.g. "TX:") and before a space (" ").
Here's one way to split on 2 delimiters. This works on Oracle 12c as you included the Oracle regexp-substr tag. Using a with statement, first set up the original data, then split on a space or the end of the line, then break into name-value pairs.
WITH tbl_original_data(ID, str) AS (
SELECT 1, 'TX:123 SP:XapZNsyeS INST:456123' FROM dual UNION ALL
SELECT 2, 'MI:321 SP:MfeKLgkrJ INST:654321' FROM dual
),
tbl_split_on_space(ID, ELEMENT) AS (
SELECT ID,
REGEXP_SUBSTR(str, '(.*?)( |$)', 1, LEVEL, NULL, 1)
FROM tbl_original_data
CONNECT BY REGEXP_SUBSTR(str, '(.*?)( |$)', 1, LEVEL) IS NOT NULL
AND PRIOR ID = ID
AND PRIOR SYS_GUID() IS NOT NULL
)
--SELECT * FROM tbl_split_on_space;
SELECT ID,
REGEXP_REPLACE(ELEMENT, '^(.*):.*', '\1') NAME,
REGEXP_REPLACE(ELEMENT, '.*:(.*)$', '\1') VALUE
FROM tbl_split_on_space;
ID NAME VALUE
---------- ---------- ----------
1 TX 123
1 SP XapZNsyeS
1 INST 456123
2 MI 321
2 SP MfeKLgkrJ
2 INST 654321
6 rows selected.
EDIT: Realizing this answer is a little more than was asked for, here's a simplified answer to return one element. Don't forget to allow for the ending of a space or the end of the line as well, in case you element is at the end of the line.
WITH tbl_original_data(ID, str) AS (
SELECT 1, 'TX:123 SP:XapZNsyeS INST:456123' FROM dual
)
SELECT REGEXP_SUBSTR(str, '.*?TX:(.*)( |$)', 1, 1, NULL, 1) TX_VALUE
FROM tbl_original_data;
TX_VALUE
--------
123
1 row selected.

Oracle regex to extract string between first pair of < and > brackets

I am have been assigned a task to parse a string (which is essentially in XML format) and I need to extract the name of the first tag in the string
eg: string '<column><data-type>string</data-type>.............'
or '<filter><condition>....</condition>...............'
or
'......................'
the string keeps changing but I am only interested in the first tag, I would like to get the output like:
column,
filter,
query
i have tried regexp_substr(string,'^<(.+)>',1,1,null,1) and some similer variations but they don't seem to be working cosistently.
Please help.
If you have XML data then use a proper XML parser:
SELECT XMLQUERY( '/*/name()' PASSING XMLTYPE(value) RETURNING CONTENT ) AS tag_name
FROM table_name
Which for the sample data:
CREATE TABLE table_name ( value CLOB );
INSERT INTO table_name ( value )
SELECT '<column><data-type>string</data-type></column>' FROM DUAL UNION ALL
SELECT '<filter><condition>....</condition></filter>' FROM DUAL UNION ALL
SELECT '<query />' FROM DUAL UNION ALL
SELECT '<has_attributes attr1="do not return this" attr2="<or> this" />' FROM DUAL
Outputs:
| TAG_NAME |
| :------------- |
| column |
| filter |
| query |
| has_attributes |
db<>fiddle here
You are looking for any character between the bounds -- and that includes '>'. So, just exclude the terminating character:
select regexp_substr(string,'^<([^>]+)>',1,1,null,1)
from (select '<column><data-type>string</data-type>.............' as string from dual union all
select '<filter><condition>....</condition>...............' from dual
) x;

How to select the list of words containing a particular substring as part of a SQL query (oracle)?

I'm trying to return the list of "words" (separated by spaces) containing a certain substring within a string as part of an Oracle Sql query. Would like to return the result as a comma separated list. Separate rows for each match would also work.
Example String in [text_col] field:
some words 123-asdf-789A and also this one 456-asdf-555A more words etc.
Desired result: 123-asdf-789A, 456-asdf-555A
This is what I have so far but it only returns the first result and the fact that it's two separate regular expressions makes it difficult to concatenate all matches as I would like to do.
CONCAT(REGEXP_SUBSTR(text_col, ''(([^[:space:]]+)\asdf)'', 1, 1, ''i'', 1),
REGEXP_SUBSTR(text_col, ''\asdf([^[:space:]]+)'', 1, 1, ''i'', 1))
You can use some regexp functions together as :
with tab(str) as
(
select 'some words 123-asdf-789A and also this one 456-asdf-555A more words etc' from dual
), t as
(
select regexp_substr(str,'[^[:space:]]+',1,level) as str, level as lvl
from tab
connect by level <= regexp_count(str,'[:space:]')
)
select listagg(str,',') within group (order by lvl) as "Result"
from t
where regexp_like(str,'-');
Result
---------------------------------
123-asdf-789A,456-asdf-555A
Demo
first split by spaces (through [:space:] posix) and take the ones containing dash characters, and finally concatenate by listagg() function
Use a recursive sub-query factoring clause and iterate through all the matches concatenating the string as you go:
Oracle Setup:
CREATE TABLE test_data ( value ) AS
SELECT 'some words 123-asdf-789A and also this one 456-asdf-555A more words etc.' FROM DUAL UNION ALL
SELECT 'some words without the expected sub-string' FROM DUAL UNION ALL
SELECT 'asdf asdf-123 456-asdf 78-asdf-90' FROM DUAL
Query:
WITH matches ( value, idx, cnt, match ) AS (
SELECT value,
0,
REGEXP_COUNT( value, '\S*asdf\S*' ),
CAST( NULL AS VARCHAR2(4000) )
FROM test_data
UNION ALL
SELECT value,
idx + 1,
cnt,
CASE idx WHEN 0 THEN '' ELSE match || ' ' END
|| REGEXP_SUBSTR( value, '\S*asdf\S*', 1, idx + 1 )
FROM matches
WHERE idx < cnt
)
SELECT value, match
FROM matches
WHERE idx = cnt;
Output:
VALUE | MATCH
:----------------------------------------------------------------------- | :--------------------------------
some words without the expected sub-string | null
some words 123-asdf-789A and also this one 456-asdf-555A more words etc. | 123-asdf-789A 456-asdf-555A
asdf asdf-123 456-asdf 78-asdf-90 | asdf asdf-123 456-asdf 78-asdf-90
db<>fiddle here

Comma-separated string match

I have this query:
SELECT regexp_replace (var_called_num, '^' ||ROUTING_PREFIX) INTO Num
FROM INCOMING_ROUTING_PREFIX
WHERE var_called_num LIKE ROUTING_PREFIX ||'%';`
INCOMING_ROUTING_PREFIX table has two rows
1) 007743
2) 007742
var_called_num is 0077438843212123. So above query gives the result 8843212123.
So basically, the query is removing prefix (longest match from table) from var_called_num.
Now my table has changed. Now it has only 1 row which is comma-separated.
Modified Table:
INCOMING_ROUTING_PREFIX table has one row which is comma-separated:
1) 007743,007742
How to modify the query to achieve the same behavior. Need to remove longest match prefix from var_called_num.
Here's one option: you'd have to split the prefix into rows, and the use it in REGEXP_REPLACE.
SQL> with
2 calnum (var_called_num) as
3 (select '0077438843212123' from dual),
4 incoming_routing_prefix (routing_prefix) as
5 (select '007743,007742' from dual),
6 --
7 irp_split as
8 (select regexp_substr(i.routing_prefix, '[^,]+', 1, level) routing_prefix
9 from incoming_routing_prefix i
10 connect by level <= regexp_count(i.routing_prefix, ',') + 1
11 )
12 select regexp_replace(c.var_called_num, '^' || s.routing_prefix) result
13 from calnum c join irp_split s on s.routing_prefix = substr(c.var_called_num, 1, length(s.routing_prefix));
RESULT
----------------
8843212123
SQL>
By the way, why did you change the model to a worse version than it was before?
you can split the values
with test as (
select regexp_substr('007743,007742','[^,]+', 1, level) as ROUTING_PREFIX from dual
connect by regexp_substr('007743,007742S', '[^,]+', 1, level) is not null
)
and that use the view in your select
SELECT regexp_replace ('0077438843212123', '^' ||ROUTING_PREFIX)
FROM test WHERE '0077438843212123' LIKE ROUTING_PREFIX ||'%';

Split by uppercase Oracle

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.