Find string value based on a string key in a given string - oracle

I have a string like so:
Directory=Voice Active Directory A,ID=VT-AD1,Location=Canada,UserName=admin,Password=passw0rd,Selector=AD1
I'm writing a function that will receive this value as parameter and another parameter as UserName
I need to find the value against key UserName from the given string which is admin
I'm searching if there is a RegEx within oracle to help out here.
Here is what I have made so far:
CREATE OR REPLACE FUNCTION GET_CSV_FIELD(Parameter_RowData IN CLOB, Parameter_Field_Name IN VARCHAR2 )
RETURN VARCHAR2
AS
Found_Index INTEGER;
End_Index INTEGER;
Pair_Index INTEGER;
Return_Result VARCHAR2(4000);
BEGIN
Found_Index := INSTR(Parameter_RowData, Parameter_Field_Name);
IF Found_Index > 0 THEN
End_Index := INSTR(Parameter_RowData, ',', Found_Index);
Pair_Index := INSTR(Parameter_RowData, '=', Found_Index);
IF End_Index = 0 THEN
Return_Result := '';
RETURN Return_Result;
END IF;
IF Pair_Index = 0 THEN
Return_Result := '';
RETURN Return_Result;
END IF;
Return_Result := SUBSTR(Parameter_RowData, Pair_Index + 1, End_Index - Pair_Index - 1);
ELSE
Return_Result := '';
END IF;
RETURN Return_Result;
END;
Any better method? Thanks.

You can do this with regular expressions:
select substr(regexp_substr(str, 'UserName=[^,]+'), 10)
The general method would be
select substr(regexp_substr(str, v_param || '=[^,]+'), length(v_param) + 2)

Related

How to return two types in pl/sql oracle

How to return two types in pl/sql oracle?
return number -- here I tell than function reurns number, but i want to return number and string when an exception is thrown
is
prPrice number; -- product price
curFrom number; -- price
pgcount number := 0; -- product count
noProductsOnDate EXCEPTION;
wrongCurrency EXCEPTION;
begin
SELECT COUNT(*) INTO pgcount
from Products pr, Outgoing outg, Incoming inc
where pr.PROD_ID = outg.PROD_ID and pr.PROD_ID = inc.PROD_ID and inc.inc_date > d
Having sum(inc.quantity) > sum(outg.quantity);
if pgcount = 0 or pgcount is null then
raise noProductsOnDate;
END IF;
if curTo > 2 OR curTo < 1 then
raise wrongCurrency;
end if;
If curTo = 1
then curFrom := 2;
Elsif curTo = 2
then curFrom := 1;
END IF;
select pric.Value*cour.value into prPrice from Prices pric, Cources cour
where p = pric.prod_id and pric.DAYFROM <= d and (pric.DAYTO >= d or pric.DAYTO is null) and cour.cur_idto = curTo and cour.cur_idfrom = curFrom;
return prPrice; -- here i wanna return number
exception
when noProductsOnDate then return '1q'; -- here i wanna return string (error message)
when wrongCurrency then return '2q'; -- here i wanna return string (error message)
end;
I can't return string in exception, because function return number
Maybe I doing something wrong,
Please, tell me how can I return several data types from one function, maybe I should do everything differently, but I don't understand how to do it ((
You can't do it that way, but can another way around - declare function to return varchar2. Then, in your code, you can
create function ...
return varchar2
is
begin
... do whatever you're doing
return to_char(poPrice);
exception
when ... then return '1q';
end;
I write my functions often in this form:
return 0 in case of success
return a positive number in case of a warning (often not used)
return a negative number in case of an error
And I use out parameters for the function results, in your case the price and/or a message.
Something along the lines of:
CREATE OR REPLACE FUNCTION my_function(vi_date IN DATE,
vo_price OUT NUMBER,
vo_msg OUT VARCHAR) RETURN INTEGER IS
BEGIN
...
IF pgcount = 0 OR pgcount IS NULL THEN
vo_msg := 'No products on that date.';
RETURN -20001; -- return custom error code
END IF;
...
IF vo_price < 0 THEN
vo_msg := 'Price is negative. Calculation my be wrong.';
RETURN 1; -- return warning flag (positive number)
ELSE
RETURN 0; -- means success
END IF;
EXCEPTION WHEN OTHERS THEN
-- Error. Return negative number. SQLCODE is always the negative ORA code
-- except for ORA-1403 which is strangely SQLCODE 100 instead
vo_msg := SQLERRM;
RETURN CASE WHEN SQLCODE = 100 THEN -1403 ELSE SQLCODE END;
END my_function;
Then call it like this:
DECLARE
v_code INTEGER;
v_price NUMBER (10,2);
v_msg VARCHAR(1000);
BEGIN
v_code := my_function(DATE '2022-09-29', v_price, v_msg);
IF v_code >= 0 THEN
DBMS_OUTPUT.PUT_LINE('The price is: ' || v_price);
END IF;
IF v_code <> 0 THEN
DBMS_OUTPUT.PUT_LINE('Message: ' || v_msg);
END IF;
END;

How to concat a string to a variable in pl/sql(oracle function)?

I am trying to create a function that outputs non-english words in a string but i am getting the following error:
PLS-00103: Encountered the symbol "|" when expecting one of the
following:
:= . ( # % ;
The symbol ":= was inserted before "|" to continue.
The code that gives the error:
CREATE OR REPLACE Function
-- ...
IS
s varchar2(38);
lang varchar2(100);
begin
s := -- ...
lang := -- ...
lang || s; -- trying to concate here
end;
The concatenation operator seems not to be working. Can anyone point out any mistake I'm making.
As OldProgrammer wrote in a comment:
lang || s
should be
lang := lang || s
The errors are:
RETURN VARCHAR2 and not RETURN string
REGEXP_LIKE returns a boolean and not a string.
lang || s; should be lang := lang || s;
Which would give you the code:
CREATE OR REPLACE Function findAssamese(
string IN varchar2
) RETURN VARCHAR2
IS
s varchar2(38);
lang varchar2(100);
begin
for i in 1..length(string) loop
s := Substr(string,i,1);
if REGEXP_LIKE (s, '[A-Z]') OR REGEXP_LIKE (s, '[a-z]') then
lang := lang || s; -- trying to concate here
end if;
end loop;
return lang;
end;
/
However, you could simply write:
CREATE OR REPLACE Function findAssamese(
string IN varchar2
) RETURN VARCHAR2
IS
begin
return REGEXP_REPLACE(string, '[^A-Z]', NULL, 1, 0, 'i');
end;
/
db<>fiddle here

Checking if word is palindrome with function

I have to write a program in Pascal which checks whether a word is a palindrome.
For example:
if I input "abba" then write 'TRUE'
input 'abb a' then write 'TRUE'
input 'abca' write 'FALSE'
I wrote this:
program palindromek;
var i,j,delka,pul:integer;
str:string;
function palindrom(slovo:string):boolean;
const mezera=32;
begin
delka:=length(str);
if (delka mod 2) = 0 then pul:=delka div 2
else pul:=(delka-1) div 2;
for i:=1 to delka do
begin
if (ord(slovo[i])>=ord('a')) and (ord(slovo[i])<=ord('z')) then
begin
if (delka>=4)and(delka<=100) then
begin
if (length(str) mod 2) = 0 then {slovo se sudym poctem pismen}
begin
for j:=1 to pul do
begin
if slovo[j]=slovo[length(str)-j+1]
then palindrom:=true else palindrom:=false
end
end else
begin
for j:=1 to pul do
begin
if slovo[j]=slovo[length(str)-j+1]
then palindrom:=true else palindrom:=false
end
end
end else if slovo[1]=slovo[delka]
then palindrom:=true else palindrom:=false
end
end;
end;
begin
readln(str);
writeln(palindrom(str));
end.
but it has to ignore spaces. Do you have any idea please?
To remove all spaces, you can use function like this:
procedure RemoveSpacesInplace(var s: string);
var
i, SpaceCount: Integer;
begin
SpaceCount := 0;
for i := 1 to Length(s) do
if s[i] = ' ' then
Inc(SpaceCount)
else
s[i - SpaceCount] := s[i];
SetLength(s, Length(s) - SpaceCount);
end;
You can modify it for other non-letter chars.
Note that your logic for odd and even length is excessive. Try to simplify it.
You can use the functions StringReplace and ReverseString for your task.
program palindromek;
uses SysUtils, StrUtils;
var
str:string;
function palindrom(slovo:string):boolean;
begin
slovo := StringReplace(slovo, ' ', '', [rfReplaceAll]);
Result := slovo = ReverseString(slovo)
end;
begin
readln(str);
writeln(palindrom(str));
readln;
end.
If you are not allowed to use SysUtils and StrUtils then you can manually reverse your string and then compare if the original string and the reversed string are equal.
This would look something like this: (not tested!)
function palindrom(slovo:string):boolean;
var slovofor: string;
slovorev: string;
i: integer;
begin
for i:= length(slovo) downto 1 do begin
if slovo[i] <> ' ' then begin
slovofor := slovofor + slovo[length(slovo)-i+1];
slovorev := slovorev + slovo[i];
end;
end;
writeln(slovofor);
Result := slovofor = slovorev
end;

fluent nhibernate calling oracle function

`i try to call an oracle function inside a package
function :
FUNCTION test_func (I_PARAMS IN TPARAMS,
O_RESPONSE_CODE OUT VARCHAR2,
O_RESPONSE_EXPLANATION OUT VARCHAR2)
RETURN BOOLEAN IS
BEGIN
O_RESPONSE_CODE := 0;
O_RESPONSE_EXPLANATION := 'Başarılı';
return true;
END test_func;
Ora test script:
declare
I_PARAMS TPARAMS;
O_RESPONSE_CODE VARCHAR2(4);
O_RESPONSE_EXPLANATION VARCHAR2(500);
reslt boolean;
begin
O_RESPONSE_EXPLANATION := ' a';
O_RESPONSE_CODE := '2';
reslt := D_PKG.test_func(I_PARAMS , O_RESPONSE_CODE , O_RESPONSE_EXPLANATION );
dbms_output.put_line(o_response_explanation || ' ' || o_response_code);
end;
it works but my fluent code does not work :S could anyone help me?
and here is it...
IQuery query = session.CreateSQLQuery("reslt := D_PKG.test_func(I _PARAMS , O_RESPONSE_CODE , O_RESPONSE_EXPLANATION )")
.SetParameter("I_PARAMS", input, NHibernateUtil.Object)
.SetString("O_RESPONSE_CODE", null)
.SetString("O_RESPONSE_EXPLANATION", null)
.SetBoolean("reslt",false);
output.RESULT = query.ExecuteUpdate();
here is my Parameter I_PARAMS does not exist as a named parameter
May be session.CreateSQLQuery("reslt := D_PKG.test_func(:I _PARAMS , :O_RESPONSE_CODE , :O_RESPONSE_EXPLANATION )"). Missed the : char?

array or list into Oracle using cfprocparam

I have a list of values I want to insert into a table via a stored procedure.
I figured I would pass an array to oracle and loop through the array but I don't see how to pass an array into Oracle. I'd pass a list but I don't see how to work with the list to turn it into an array using PL/SQL (I'm fairly new to PL/SQL). Am I approaching this the wrong way?
Using Oracle 9i and CF8.
EDIT
Perhaps I'm thinking about this the wrong way? I'm sure I'm not doing anything new here...
I figured I'd convert the list to an associative array then loop the array because Oracle doesn't seem to work well with lists (in my limited observation).
I'm trying to add a product, then add records for the management team.
-- product table
productName = 'foo'
productDescription = 'bar'
...
...
etc
-- The managementteam table just has the id of the product and id of the users selected from a drop down.
The user IDs are passed in via a list like "1,3,6,20"
How should I go about adding the records to the management team table?
Here is where I am code wise
In theory I pass a list "1,2,3,4" to inserts.addProduct.
inserts.addProduct should call tools.listToArray and return an array.
inserts.addProduct recreates a list with a * delim as a test.
CREATE OR REPLACE PACKAGE tools AS
TYPE array_type is TABLE OF VARCHAR2(225) INDEX BY BINARY_INTEGER;
FUNCTION listToArray(in_list IN VARCHAR,
in_delim IN VARCHAR2 DEFAULT ',')
RETURN array_type;
END tools;
CREATE OR REPLACE PACKAGE BODY tools
AS
FUNCTION listToArray(in_list IN VARCHAR,
in_delim IN VARCHAR2 DEFAULT ',')
RETURN array_type
IS
l_token_count BINARY_INTEGER := 0;
-- l_token_tbl type_array;
i pls_integer;
l_start_pos INTEGER := 1;
l_end_pos INTEGER :=1;
p_parsed_table array_type;
BEGIN -- original work by John Spencer
WHILE l_end_pos <> 0 LOOP
l_end_pos := instr(in_list,in_delim,l_start_pos);
IF l_end_pos <> 0 THEN
l_token_count := l_token_count + 1;
p_parsed_table(l_token_count ) :=
substr(in_list,l_start_pos,l_end_pos - l_start_pos);
l_start_pos := l_end_pos + 1;
END IF;
END LOOP;
IF l_token_count = 0 THEN /* We haven't parsed anything so */
l_token_count := 1;
p_parsed_table(l_token_count) := in_list;
ELSE /* We need to get the last token */
l_token_count := l_token_count + 1;
p_parsed_table(l_token_count) := substr(in_list,l_start_pos);
END If;
RETURN p_parsed_table;
END listToArray; -- Procedure
END tools;
CREATE OR REPLACE PACKAGE inserts AS
TYPE array_type is TABLE OF VARCHAR2(225) INDEX BY BINARY_INTEGER;
PROCEDURE addProduct (inList IN VARCHAR2,
outList OUT VARCHAR2
);
END inserts;
CREATE OR REPLACE PACKAGE BODY inserts
AS
PROCEDURE addProduct (inList IN VARCHAR2,
outList OUT VARCHAR2
)
IS
i NUMBER;
localArray array_type := tools.listToArray(inList);
BEGIN
outList := '';
FOR i IN localArray.first .. localArray.last LOOP
outList := outList || '*' ||localArray(i); -- return a string just to test this mess
END LOOP;
END addProduct;
END inserts;
I'm currently getting an error "PLS-00382: expression is of wrong type" on localArray array_type := tools.listToArray(inList);
final working code (thanks so much!)
-- create sql type collection
CREATE OR REPLACE TYPE array_type is TABLE OF VARCHAR2(225);
/
CREATE OR REPLACE PACKAGE tools AS
FUNCTION listToArray(in_list IN VARCHAR,
in_delim IN VARCHAR2 DEFAULT ',')
RETURN array_type;
END tools;
/
CREATE OR REPLACE PACKAGE BODY tools
AS
FUNCTION listToArray(in_list IN VARCHAR,
in_delim IN VARCHAR2 DEFAULT ',')
RETURN array_type
IS
l_token_count BINARY_INTEGER := 0;
i pls_integer;
l_start_pos INTEGER := 1;
l_end_pos INTEGER :=1;
p_parsed_table array_type := array_type();
BEGIN
WHILE l_end_pos <> 0 LOOP
l_end_pos := instr(in_list,in_delim,l_start_pos);
IF l_end_pos <> 0 THEN
p_parsed_table.extend(1);
l_token_count := l_token_count + 1;
p_parsed_table(l_token_count ) :=
substr(in_list,l_start_pos,l_end_pos - l_start_pos);
l_start_pos := l_end_pos + 1;
END IF;
END LOOP;
p_parsed_table.extend(1);
IF l_token_count = 0 THEN /* We haven't parsed anything so */
l_token_count := 1;
p_parsed_table(l_token_count) := in_list;
ELSE /* We need to get the last token */
l_token_count := l_token_count + 1;
p_parsed_table(l_token_count) := substr(in_list,l_start_pos);
END If;
RETURN p_parsed_table;
END listToArray; -- Procedure
END tools;
/
CREATE OR REPLACE PACKAGE inserts AS
PROCEDURE addProduct (inList IN VARCHAR2,
outList OUT VARCHAR2
);
END inserts;
/
CREATE OR REPLACE PACKAGE BODY inserts
AS
PROCEDURE addProduct (inList IN VARCHAR2,
outList OUT VARCHAR2
)
IS
i NUMBER;
mylist VARCHAR(100);
localArray array_type := array_type();
BEGIN
localArray := tools.listToArray(inList);
mylist := '';
FOR i IN localArray.first .. localArray.last LOOP
mylist := mylist || localArray(i) || '*';
END LOOP;
aList := mylist;
END addProduct;
END inserts;
/
PL/SQL has supported arrays since Oracle 8.0. They used to be called PL/SQL tables which confused the heck out of everybody, so now they are called collections. Find out more.
The problem is, that they are implemented as User-Defined Types (i.e. objects). My reading of the ColdFusion documents suggests that cfprocparam only supports the "primitive" datatypes (number, varchar2, etc). So UDTs are not supported.
I'm not sure what you mean by this:
I'd pass a list but I don't see how to
work with the list to turn it into an
array using PL/SQL
If you mean you want to pass a string of comma separated values ....
"Fox in socks, Mr Knox, Sam-I-Am, The Lorax"
then I have a workaround for you. Oracle doesn't provide a built-in Tokenizer. But a long time ago John Spencer published a hand-rolled solution which works in Oracle 9i on the OTN forums. Find it here.
edit
but... Oracle hates me
Do not despair. The OTN forums have been upgraded a few times since John posted that , and the formatting seems to have corrupted the code somewhere along the way. There were a couple of compilation errors which it didn't use to have.
I have rewritten John's code, including a new function. THe main difference is that the nested table is declared as a SQL type rather than a PL/SQL type.
create or replace type tok_tbl as table of varchar2(225)
/
create or replace package parser is
function my_parse(
p_str_to_search in varchar2
, p_delimiter in varchar2 default ',')
return tok_tbl;
procedure my_parse(
p_str_to_search in varchar2
, p_delimiter in varchar2 default ','
, p_parsed_table out tok_tbl);
end parser;
/
As you can see, the function is just a wrapper to the procedure.
create or replace package body parser is
procedure my_parse ( p_str_to_search in varchar2
, p_delimiter in varchar2 default ','
, p_parsed_table out tok_tbl)
is
l_token_count binary_integer := 0;
l_token_tbl tok_tbl := tok_tbl();
i pls_integer;
l_start_pos integer := 1;
l_end_pos integer :=1;
begin
while l_end_pos != 0
loop
l_end_pos := instr(p_str_to_search,p_delimiter,l_start_pos);
if l_end_pos != 0 then
l_token_count := l_token_count + 1;
l_token_tbl.extend();
l_token_tbl(l_token_count ) :=
substr(p_str_to_search,l_start_pos,l_end_pos - l_start_pos);
l_start_pos := l_end_pos + 1;
end if;
end loop;
l_token_tbl.extend();
if l_token_count = 0 then /* we haven't parsed anything so */
l_token_count := 1;
l_token_tbl(l_token_count) := p_str_to_search;
else /* we need to get the last token */
l_token_count := l_token_count + 1;
l_token_tbl(l_token_count) := substr(p_str_to_search,l_start_pos);
end if;
p_parsed_table := l_token_tbl;
end my_parse;
function my_parse ( p_str_to_search in varchar2
, p_delimiter in varchar2 default ',')
return tok_tbl
is
rv tok_tbl;
begin
my_parse(p_str_to_search, p_delimiter, rv);
return rv;
end my_parse;
end parser;
/
The virtue of declaring the type in SQL is that we can use it in a FROM clause like this:
SQL> insert into t23
2 select trim(column_value)
3 from table(parser.my_parse('Fox in socks, Mr Knox, Sam-I-Am, The Lorax'))
4 /
4 rows created.
SQL> select * from t23
2 /
TXT
------------------------------------------------------------------------------
Fox in socks
Mr Knox
Sam-I-Am
The Lorax
SQL>

Resources