String Pattern Matching in Sql / Pl/sql - sql

I need to match a string to a pattern to validate the given string.
The given string could be like this 1234/5678.
I should validate the string in such a way that the first four and the last four characters will have to be numbers and they must be seperated by a slash.
How can I do this in SQL or PL/SQL?
I tried different functions such as REGEXP_LIKE, REGEXP_REPLACE,REGEXP_SUBSTR.
Can anyone please help me on this?

If this needs to be done in PL/SQL (e.g. you're validating user input, rather than data in a table), you can create a function to do the validation, e.g.:
DECLARE
v_str VARCHAR2(10);
FUNCTION validate_string (in_str VARCHAR2) RETURN BOOLEAN
IS
BEGIN
RETURN regexp_like(in_str, '\d{4}/\d{4}');
END validate_string;
PROCEDURE validation_output (in_str VARCHAR2)
IS
BEGIN
IF validate_string (in_str => in_str) THEN
dbms_output.put_line(in_str||': validated');
ELSE
dbms_output.put_line(in_str||': not validated');
END IF;
END validation_output;
BEGIN
v_str := '1234/5678';
validation_output (v_str);
v_str := '12/5678';
validation_output (v_str);
v_str := NULL;
validation_output (v_str);
END;
/
1234/5678: validated
12/5678: not validated
: not validated

if you are using oracle you can user regexp_like
https://www.techonthenet.com/oracle/regexp_like.php
if you are using mysql regexp or rlike
https://dev.mysql.com/doc/refman/5.5/en/regexp.html
for sqlserver IsMatch()
https://github.com/zzzprojects/Eval-SQL.NET/wiki/SQL-Server-Regex-%7C-Use-regular-expression-to-search,-replace-and-split-text-in-SQL#sql-regex---ismatch
ORACLE
SELECT * FROM T WHERE COL REGEXP_LIKE REGULAREXP
MYSQL
SELECT * FROM T WHERE COL RLIKE REGULAREXP
SELECT * FROM T WHERE COL REGEXP REGULAREXP

sample table:
SELECT * FROM ns_98;
4321/4567
43/45
43898/4521
4388/4521
43885/45215
4388///4521
SELECT a
FROM ns_98
WHERE REGEXP_LIKE (a,'^[0-9]{4}/{1}[0-9]{4}$');
output:
4321/4567
4388/4521

Related

Oracle SQL: How to replace within all members of a list

Using Oracle SQL...
I'd like to use the replace function on all values of a hardcoded list. Something like this...
WHERE (
(field IN replace(('PREFIX-ITEM0','PREFIX-ITEM1','PREFIX-ITEM2','PREFIX-ITEM3','PREFIX-ITEM4','PREFIX-ITEM5','PREFIX-ITEM6','PREFIX-ITEM7','PREFIX-ITEM8','PREFIX-ITEM9'),'PREFIX-','NEWBIE-'))
)
Is there any way to do this?
If you have a fixed list of values - so they aren't coming from a table - then it would be much simpler to modify them externally before putting them into a query.
But if for some reason you can't do that, you could treat the list as a varray of strings, and use a function to replace them individually. In recent versions of Oracle you can do that with a local function defined in a with clause:
with
function myfunc (p_in_list sys.odcivarchar2list, p_old varchar2, p_new varchar2)
return sys.odcivarchar2list is
l_out_list sys.odcivarchar2list;
begin
l_out_list := new sys.odcivarchar2list();
l_out_list.extend(p_in_list.count);
for i in p_in_list.first..p_in_list.last loop
l_out_list(i) := replace(p_in_list(i), p_old, p_new);
end loop;
return l_out_list;
end;
select field
from t
where field in (
select * from myfunc(
sys.odcivarchar2list('PREFIX-ITEM0','PREFIX-ITEM1','PREFIX-ITEM2','PREFIX-ITEM3','PREFIX-ITEM4','PREFIX-ITEM5','PREFIX-ITEM6','PREFIX-ITEM7','PREFIX-ITEM8','PREFIX-ITEM9'),
'PREFIX-',
'NEWBIE-')
)
/
which with some dummy data with a mix of PREFIX and NEWBIE values produces:
FIELD
------------
NEWBIE-ITEM2
NEWBIE-ITEM3
NEWBIE-ITEM4
db<>fiddle

Find invalid numbers - Oracle SQL

I have a table:
table1
column_name value
Test1 80933Y355220
Test1 8093363X5220
Test1 809336355220
Test1 80.98
Test1 -80.98
Test2 1234
Test2 abc
Test2 12-23-09
I need to identify all the invalid number values present in the column value
Output should be:
column_name value
Test1 80933Y355220
Test1 8093363X5220
Test2 abc
Test2 12-23-09
Is there a way to get this list?
The common way to solve this is with a user-defined function:
create or replace function is_number (p_str in varchar2) return varchar2 is
n number;
rv varchar2(1);
begin
begin
n := to_number(p_str);
rv := 'Y';
exception
when others then
rv := 'N';
end;
return rv;
end;
/
select column_name, value, is_number(value) as is_number
from table1
where is_number(value) = 'N'
/
In Oracle 12c R2 we acquired a built-in function to do it: validate_conversion() which handles lots of data types. Find out more.
select column_name
, value
from table1
where validate_conversion(value as number) = 0
/
Here is the inevitable demo on db<>fiddle.
Regex solutions are tricky to get right. It's easy to formulate expressions which exclude valid numbers (such as -80.98) or include non-numbers (such as (12-34-56). Even we do get that bit right (as Gordon's solution does) what happens if we want to allow decimal separators or currency symbols? Or scientific notation? That's a messy regex. It's easy to extend a UDF to handle a format mask and validate_conversion() does it natively:
SELECT VALIDATE_CONVERSION('$100,00' AS NUMBER,
'$999D99', 'NLS_NUMERIC_CHARACTERS = '',.''')
FROM DUAL;
I would use regexp_like() with this pattern:
SELECT column_name, value
FROM table1
WHERE NOT REGEXP_LIKE(value, '^[-]?[0-9]*[.]?[0-9]*$')
Just to give an Oracle 12.1 answer, it doesn't have validate_conversion or the on conversion error clause of to_date, but it does support PL/SQL functions in a WITH clause, allowing something like this:
with function is_number(str varchar2) return varchar2
as
n number;
begin
n := str; return 'Y';
exception
when others then return 'N';
end;
select d.column_name
, d.value
from demo d
where is_number(d.value) = 'N'

How to make a function that takes code like "SELECT * FROM SOME_TABLE" as an input and returns a table as an output?

I want to create a function that takes some code as an input (e.g. Select * FROM SOME_TABLE) and returns the result of a query as an output.
I want to use it in procedures in order to return tables as a result.
It should look like this:
BEGIN
--some procedure code
CREATE TABLE SOME_TABLE as Select * FROM ...;
Select * FROM table(my_function('Select * FROM SOME_TABLE'));
END;
Important tips:
The resulting table can have multiple columns, from 1 to +inft
The resulting table can have multiple rows, from 1 to +inft
So the size of a table can be both very small or very large.
The input query can have several where, having, partition, and other Oracle constructions.
I want to have a table as an output, not DBMS_OUTPUT.
I can't install any modules/applications, or use other languages hints. However, I can manually create types, functions, procedures.
I tried to search in the net but could not find a solution that meets all my expectations. The best link I've found was this:
https://sqljana.wordpress.com/2017/01/22/oracle-return-select-statement-results-like-sql-server-sps-using-pipelined-functions/
DBMS_SQL.RETURN_RESULT works if your "code" is a select query
DECLARE
l_cur SYS_REFCURSOR;
l_query VARCHAR2(4000) := 'select * from SOME_TABLE';
BEGIN
OPEN l_cur for l_query;
DBMS_SQL.RETURN_RESULT(l_cur);
END;
/
you can create a function that has a string as parameter and return a cursor.
select statement you should pass as a string. in a function you can open a Cursor.
declare
v_sql varchar2(100) := 'select 1,2,3,4,5 from dual';
cur_ref SYS_REFCURSOR;
function get_data(in_sql in varchar2) return SYS_REFCURSOR
as
cur_ret SYS_REFCURSOR;
begin
OPEN cur_ret FOR in_sql;
return cur_ret;
end;
begin
:cur_ref := get_data(v_sql);
end ;
if your select statement is longer than 32K than you maybe should use a clob instead of varchar2 for your Parameter type. But you have to try that

Oracle : large Number getting converted scientific notation (40 digits) on concatenation

Oracle converts Number to string on concatenation or moving it to_char.
Example:
select value from tab;
value
9076725748515642018090620180906173606980000000000000000000000000000000000000000
select RPAD(value,LENGTH(value)+1,chr(135)) from tab;
RPAD(value,LENGTH(value)+1,chr(135))
9.0767257485156420180906201809061736E+78‡
Intended result
9076725748515642018090620180906173606980000000000000000000000000000000000000000‡
Maybe PL/SQL can help you. You can try below script.
CREATE OR REPLACE FUNCTION test123 (p_number NUMBER) return VARCHAR2
IS
v_no VARCHAR2(100);
BEGIN
EXECUTE IMMEDIATE
'select '''||p_number||'''||CHR(135) '||
' from dual'
INTO v_no;
RETURN v_no;
END;
/
SELECT TEST123(9076725748515642018090620180906173606980000000000000000000000000000000000000000)
FROM DUAL;
OUTPUT
--------------------------------------------------------------------------------
9076725748515642018090620180906173606980000000000000000000000000000000000000000‡

PL-SQL stored procedure split string

What I would like to do is this:
In java I have an array like ['AB','BC','CD','DE'] which I want to concat to something like "AB,BC,CD,DE" and send it to the procedure as an argument.
In the procedure, my idea is, I would like to do something like
v_passedArgs --(AB,BC,CD,DE)
SELECT * FROM SOME_TABLE WHERE SOME_COL IN (v_passedArgs.split(','))
Is it possible to do something like that or maybe you have another idea?
Thank you
You can create a split function in the database and use it for splitting a string in SQL which has delimiters(',' in your example)
Is there a function to split a string in PL/SQL?
Refer the above link to create a split function and use it in your select statement
You have to create your own function.
You can work with an Oracle PL/SQL collection; here is a piece of code to return such a collection, from an input string list (p_list) with a given separator (p_sep):
CREATE OR REPLACE TYPE t_my_list AS TABLE OF VARCHAR2(100);
CREATE OR REPLACE
FUNCTION cto_table(p_sep in Varchar2, p_list IN VARCHAR2)
RETURN t_my_list
AS
l_string VARCHAR2(32767) := p_list || p_sep;
l_sep_index PLS_INTEGER;
l_index PLS_INTEGER := 1;
l_tab t_my_list := t_my_list();
BEGIN
LOOP
l_sep_index := INSTR(l_string, p_sep, l_index);
EXIT
WHEN l_sep_index = 0;
l_tab.EXTEND;
l_tab(l_tab.COUNT) := TRIM(SUBSTR(l_string,l_index,l_sep_index - l_index));
l_index := l_sep_index + 1;
END LOOP;
RETURN l_tab;
END cto_table;
/
Then how to use it with the TABLE keyword in your SELECT - the TABLE keyword converts the collection into a object usable inside Oracle SQL queries:
SELECT * FROM SOME_TABLE WHERE SOME_COL IN (
select * from TABLE(cto_table(',', v_passedArgs))
)