I am struggling to build a regexp_like statement that will work in Oracle. I need to compare a series of rows, each of which has a field that contains a comma-delimited set of numbers. (always numbers). I need to activate and inactivate accounts (daily) based on how these numbers change.
Here are several samples of the fields. (each row below is the result in the field)
9,18,31,32,50,725
17,20,31,32,50,725
17,18,20,22,50,725
9,18,31,49,50,500
49,22,9,25,222
18,18,31,9,50,725
49,31,9,25,292
I need to find any row that has one or more of the following numbers. 9, 20, 22, 50. (Other places in the code may need only 9 or only 20 and 22. But the principle holds. If the number is 500, it cannot be selected. It must be 50.
The following regular expression works in python, in my notepad search, and in an online regex builder:
((?<![1-9])9|(?<![1-9])20(?![1-9])|(?<![1-9])22(?![1-9])|(?<![1-9])50(?![1-9]))
It relies on negative lookahead and negative lookbehind. But because Oracle doesn't support lookaround, I'm stumped.
Here is a piece of sample code which works if I use regexp without lookaround.
DECLARE
v_search_string varchar2(60);
BEGIN
v_search_string := '49,31,9,25,50,292';
IF REGEXP_LIKE( v_search_string, '((?<![1-9])9|(?<![1-9])20(?![1-9])|(?<![1-9])22(?![1-9])|(?<![1-9])50(?![1-9]))')
THEN
dbms_output.put_line('Yes');
ELSE
dbms_output.put_line('No');
END IF;
--dbms_output.put_line('Yes');
END;
In this case, I should get 'Yes' in my dbms_output because it should match '50'.
Any thoughts? P.S. I'm open to someone saying, "hey, silly, it would be easier to do THIS."
CodePudding user response:
I wouldn't even use regex here:
DECLARE
v_search_string varchar2(60);
BEGIN
v_search_string := '49,31,9,25,50,292';
IF ',' || v_search_string || ',' LIKE '%,9,%' OR ',' || v_search_string || ',' LIKE '%,20,%' OR ',' || v_search_string || ',' LIKE '%,22,%' OR ',' || v_search_string || ',' LIKE '%,50,%'
THEN
dbms_output.put_line('Yes');
ELSE
dbms_output.put_line('No');
END IF;
--dbms_output.put_line('Yes');
END;
To be clear here, we are comparing ,49,31,9,25,50,292,
against e.g. %,9,%
to search for the number 9
somewhere in the CSV string. This approach may actually outperform REGEXP_LIKE
as it does not use regular expressions.
CodePudding user response:
...
where regexp_like(your_string, '(,|^)(9|20|22|50)(,|$)')
...
Generally I agree with Tim Biegeleisen - use standard string functions as much as possible.
In this case, a single regexp search may do better than four standard string searches of the same string; and the regexp approach is more flexible. You can rewrite the regular expression as
'(,|^)(' || things_to_search || ')(,|$)'
and let things_to_search
be a user input, or come from a table, etc. (it would be a pipe-delimited list of numbers you must match). If you use it as a bind variable, you get the benefit of soft parsing (the query doesn't need to be parsed again whenever you change the list).
CodePudding user response:
@mathguy. Thanks for taking my complex statement to a single, clear statement.
Starts with either a comma or start of line; ends with either a comma or end of line; plus the stuff in the middle. Change the variables for the things to search and let 'r rip.
Here's the modified sql.
DECLARE
v_search_string varchar2(60);
v_things_to_search varchar2(60);
BEGIN
v_search_string := '9,31,29,25,520,500';
v_things_to_search := '9|20|22|50';
IF REGEXP_LIKE( v_search_string, '(,|^)(' || v_things_to_search || ')(,|$)')
THEN
dbms_output.put_line('Yes');
ELSE
dbms_output.put_line('No');
END IF;
--dbms_output.put_line('Yes');
END;