Oracle SQL: Searching for $ in Regexp - regex

I want to search my response field to find any instance where a dollar sign $ is not followed by a numerical value. 1 or 2 spaces before a numerical value is ok, but there shouldn't be any text values following $.
I have the following query below:
SELECT * FROM RESPONSES
WHERE (regexp_like(response, '(\$)(\s){1,2}[^0-9]'));
This should be able to identify responses that have "$ NA". Most responses will contain a combination of $ followed by numeric values and $ by text values.
I've tried a couple of variations of the above query without any success. Any thoughts?

You can use this:
SELECT *
FROM dual
WHERE
SIGN(REGEXP_INSTR (RESPONSE, '(\$)(\s){2}[^0-9]'))=0

Include the space character in your negated character set
Since a space character qualifies as a non-digit character, a second space can give a "false positive" for the data set you want to find.
SCOTT#db>WITH smple AS (
2 SELECT
3 '23 dkf $ 1' response
4 FROM
5 dual
6 UNION ALL
7 SELECT
8 '23 dkfg gjg $ 4'
9 FROM
10 dual
11 UNION ALL
12 SELECT
13 '$ NA'
14 FROM
15 dual
16 ) SELECT
17 s.*
18 FROM
19 smple s
20 WHERE
21 ( REGEXP_LIKE ( s.response,
22 '\$\s{1,2}[^ 0-9]+' ) );
RESPONSE
----------
$ NA

You may use :
select * from responses where regexp_like(a, '^\$\s')
to get values begin with a $ sign and followed with at least one space as consecutive character(s).
with t as
(
select '$ 524' as a from dual union all
select '$524' as a from dual union all
select '$ s67e' as a from dual union all
select '# 67e' as a from dual union all
select '$s67e' as a from dual union all
select '$#67e' as a from dual
)
select * from t where regexp_like(a, '^\$\s')
A
----
$ 524
$ s67e
Demo

Related

Oracle REGEXP_LIKE logical and matching of substrings in string

I have a string containing codes like 'code1 code2 code3'. It should return the string if all codes entered are contained in the string.
For example:
select * from (
select 'avs cde jkl' code from dual)
where REGEXP_LIKE(code, 'REGEX-MAGIC')
When the regex is now something like ^(?=.*\bjkl\b)(?=.*\bavs\b).*$ then it should return the code. But this syntax is not working for regex in oracle.
The logic is 'if all codes looked for are in the string (order does not matter), then return the code.'
I have researched and this would be achievable with a positive lookahead, but oracle does not support this as far as I know. I would search for one regex and not a construct like REGEXP_LIKE(...,..) and REGEXP_LIKE(...,..) and ....
The Oracle Version is 12c.
Any help would be appreciated!
Oracle does not support look-ahead, look-behind or word boundaries in regular expressions.
If you have the sample data:
CREATE TABLE table_name (code) AS
SELECT 'avs cde jkl' FROM DUAL UNION ALL
SELECT 'avs cde' FROM DUAL UNION ALL
SELECT 'jkl avs' FROM DUAL UNION ALL
SELECT 'cde jkl' FROM DUAL;
Option 1:
The simplest query is to not use regular expressions and to look for sub-string matches using multiple LIKE conditions:
SELECT code
FROM table_name
WHERE ' ' || code || ' ' LIKE '% avs %'
AND ' ' || code || ' ' LIKE '% jkl %'
Which outputs:
CODE
avs cde jkl
jkl avs
Option 2:
You could use (slower) regular expressions with multiple REGEXP_LIKE conditions:
SELECT code
FROM table_name
WHERE REGEXP_LIKE(code, '(^| )avs( |$)')
AND REGEXP_LIKE(code, '(^| )jkl( |$)')
Which outputs the same as above.
Option 3:
You could put the matches into a sub-query factoring clause and then use a LATERAL join:
WITH match_conditions (match) AS (
SELECT 'avs' FROM DUAL UNION ALL
SELECT 'jkl' FROM DUAL
)
SELECT code
FROM table_name t
CROSS JOIN LATERAL (
SELECT 1
FROM match_conditions
WHERE ' ' || code || ' ' LIKE '% ' || match || ' %'
HAVING COUNT(*) = (SELECT COUNT(*) FROM match_conditions)
)
Which outputs the same as above.
Option 4:
If you really want a single regular expression then you can generate each permutation of the codes to match and concatenate them into a single regular expression:
SELECT code
FROM table_name
WHERE REGEXP_LIKE(
code,
'(^| )avs( | .*? )jkl( |$)' -- Permutation 1
|| '|(^| )jkl( | .*? )avs( |$)' -- Permutation 2
)
Which outputs the same as above.
However, this is going to get problematic to maintain as the number of codes to match grows as, for 2 items there are 2 permutations but for 5 items there are 5! = 120 permutations.
Option 5:
You could declare a nested table collection:
CREATE TYPE string_list AS TABLE OF VARCHAR2(20);
Then split the string (again, you do not need slow regular expressions) and then compare it to a nested table:
WITH bounds (rid, code, spos, epos) AS (
SELECT ROWID, code, 1, INSTR(code, ' ', 1)
FROM table_name
UNION ALL
SELECT rid, code, epos + 1, INSTR(code, ' ', epos + 1)
FROM bounds
WHERE epos > 0
)
SEARCH DEPTH FIRST BY code SET order_rn
SELECT MAX(code) AS code
FROM bounds
GROUP BY rid
HAVING string_list('avs', 'jkl') SUBMULTISET OF CAST(
COLLECT(
CAST(
CASE epos
WHEN 0
THEN SUBSTR(code, spos)
ELSE SUBSTR(code, spos, epos - spos)
END
AS VARCHAR2(20)
)
)
AS string_list
);
Depending on the client application you are using, you can pass the entire string_list('avs', 'jkl') collection in as a single bind variable that you can populate from an array. Java (and some languages built on top of Java) using an ODBC driver can do this; C# cannot directly but you can pass an associative array and convert it to a nested table collection with a helper function.
Which outputs the same as above.
db<>fiddle here
I'm not good at regex-magix, but - see if something like this helps.
This is a table that contains those codes:
SQL> select * from codes;
ID CODE
---------- -----------
1 avs cde jkl
2 xyz avs
Query
splits every code into rows (t_split CTE)
does the same for the entered parameter (par_string) value (p_split CTE)
why? So that they could act as if they were rows in a table, and you can apply the MINUS set operator
if MINUS returns nothing, there's a match; otherwise it's a mismatch
SQL> with
2 -- split code to rows
3 t_split as
4 (select id,
5 code original_code,
6 regexp_substr(code, '[^ ]+', 1, column_value) code
7 from codes cross join
8 table(cast(multiset(select level from dual
9 connect by level <= regexp_count(code, ' ') + 1
10 ) as sys.odcinumberlist))
11 where id = &&par_id
12 ),
13 -- split parameter to rows
14 p_split as
15 (select regexp_substr('&&par_string', '[^ ]+', 1, level) code
16 from dual
17 connect by level <= regexp_count('&&par_string', ' ') + 1
18 )
19 --
20 -- if all parameter's "pieces" of code are contained in CODE value, MINUS returns nothing
21 -- so there's a match
22 select distinct t.original_code,
23 '&&par_string' par_string,
24 case when (select count(*)
25 from (select code from t_split
26 minus
27 select code from p_split
28 )
29 ) = 0 then 'Match'
30 else 'Mismatch'
31 end result
32 from t_split t
33 where t.id = &&par_id;
Enter value for par_id: 1
Enter value for par_string: jkl avs cde
ORIGINAL_CO PAR_STRING RESULT
----------- ----------- --------
avs cde jkl jkl avs cde Match
SQL> undefine par_string
SQL> /
Enter value for par_string: avs jkl www
ORIGINAL_CO PAR_STRING RESULT
----------- ----------- --------
avs cde jkl avs jkl www Mismatch
SQL>
Depending on tool you use (this is SQL*Plus), you might need to replace && with a colon :; or, convert such a piece of code to a function.

check if string has the format : 2 lettes au max following with numbers with regexp_like oracle

Could you please tell me the expression regexp_like to check if a string has the format which begins with one or two letters max followed by numbers. For example, like 'A25', 'AB567'.
Thanks
How about
SQL> with test (col) as
2 (select 'A25' from dual union all
3 select 'AB567' from dual union all
4 select 'A12A532A' from dual union all
5 select 'ABC123' from dual union all
6 select '12XYZ34' from dual
7 )
8 select col,
9 case when regexp_like(col, '^[[:alpha:]]{1,2}[[:digit:]]+$') then 'OK'
10 else 'Wrong'
11 end result
12 from test;
COL RESULT
---------- ----------
A25 OK
AB567 OK
A12A532A Wrong
ABC123 Wrong
12XYZ34 Wrong
SQL>
The regular expression would be ^[A-Z]{1,2}[0-9]+$.
Working demo on db<>fiddle here
This match a string that contain only numbers and letters, that start with a letter, when there is never more than 2 letters in a row.
^(([A-Za-z]){1,2}([0-9])+)*\2{0,2}$

matching patterns for regexp_like in Oracle to include a group of character conditionally

I tried to look up for a good documentation for matching pattern for use of regexp_like in Oracle. I have found some and followed their instructions but looks like I have missed something or the instruction is not comprehensive.
Let's look at this example:
SELECT * FROM
(
SELECT 'ABC' T FROM DUAL
UNION
SELECT 'WZY' T FROM DUAL
UNION
SELECT 'WZY_' T FROM DUAL
UNION
SELECT 'WZYEFG' T FROM DUAL
UNION
SELECT 'WZY_EFG' T FROM DUAL
) C
WHERE regexp_like(T, '(^WZY)+[_]{0,1}+[A-Z]{0,6}')
What I expect to receive are WZY and WZY_EFG. But what I got was:
What I would like to have is the "_" could be present or not but if there are character after the first group, it is mandatory that it be present only once.
Is there a clean way to do this?
Use a subexpression grouping to make sure the _ character appears only with Capitalized Alphabetical Characters
Yes, your pattern does not address the conditional logic you need (only see the _ when capitalized alphabetical characters follow).
Placing the _ character in with a capitalized alphabetical character list into a subexpression grouping forces this logic.
Finally, placing the end of line anchor addresses the zero match scenarios.
SCOTT#DB>SELECT
2 *
3 FROM
4 (
5 SELECT 'ABC' t FROM dual
6 UNION ALL
7 SELECT 'WZY' t FROM dual
8 UNION ALL
9 SELECT 'WZY_' t FROM dual
10 UNION ALL
11 SELECT 'WZYEFG' t FROM dual
12 UNION ALL
13 SELECT 'WZY_EFG' t FROM dual
14 ) c
15 WHERE
16 REGEXP_LIKE ( t, '^(WZY)+([_][A-Z]{1,6}){0,1}$' );
T
__________
WZY
WZY_EFG

Query for regular expression - oracle DB

I am trying to get all the name which has special char and numbers in it. I want to know if there is a better way of writing this query. Thanks
select Name from TABLE1
WHERE NAME LIKE '%-%'
OR NAME LIKE '%$%'
OR NAME LIKE '%4%' etc
Try this:
SELECT Name FROM Test WHERE REGEXP_LIKE(Name,'(-|$|4)');
The | (OR or Alternation) operator allows the expression to return true if the value contains an '-' OR an '$' OR an '4' etc.
Use square brackets to define a character class. Also a full regex to anchor the pattern to the beginning of the string, any number of any characters before a character class consisting of a dash or a 4 or a dollar sign then any number of any characters anchored to the end of the string:
SQL> with tbl(name) as (
2 select 'efs' from dual
3 union
4 select 'abc-' from dual
5 union
6 select 'a4bd' from dual
7 union
8 select 'gh$dll' from dual
9 union
10 select 'xy5zzy' from dual
11 )
12 select name from tbl
13 where regexp_like(name, '^.*[-|$|4].*$');
NAME
------
a4bd
abc-
gh$dll
SQL>

how to find consecutive repetitive characters in oracle column

Is there any way to find consecutive repetitive characters like 1414, 200200 in a varchar column of an oracle table.
how can we achieve it with regexp ?
Im failing to achieve it with regexp
im my example i can get a consecutive repetition of a number but not a pattern
select regexp_substr('4120066' ,'([[:alnum:]])\1', 7,1,'i') from dual; -- getting output as expected
select regexp_substr('6360360' ,'([[:alnum:]])\1', 7,1,'i') from dual; -- i want to select this also as i have 360 followed by 360
You should be able to use something like this:
[...] WHERE REGEXP_LIKE(field, '(\d+?)\1')
If you're looking for any repetition of characters, or:
[...] WHERE REGEXP_LIKE(field, '^(\d+?)\1$')
If you want to check the whole string in the field.
\d+? will match digits.
( ... ) will store those digits.
\1 refers to the captured digits.
Note: Change to \d to . if you are not checking digits only.
Try this :
SQL> WITH t AS
2 (SELECT '1414,200200,11,12,33,33,1234,1234' test_string
3 FROM DUAL)
4 SELECT LTRIM (SYS_CONNECT_BY_PATH (test_string, ','), ',') names
5 FROM (SELECT ROW_NUMBER () OVER (ORDER BY test_string) rno, test_string
6 FROM (SELECT DISTINCT REGEXP_SUBSTR (test_string,
7 '[^,]+',
8 1,
9 LEVEL
10 ) test_string
11 FROM t
12 CONNECT BY LEVEL <=
13 LENGTH (test_string)
14 - LENGTH (REPLACE (test_string,
15 ',',
16 NULL
17 )
18 )
19 + 1))
20 WHERE CONNECT_BY_ISLEAF = 1 AND ROWNUM = 1
21 CONNECT BY rno = PRIOR rno + 1;
NAMES
--------------------------------------------------------------------------------
11,12,1234,1414,200200,33
None of the delimited string repeat !