extract some characters with instr - plsql

in pl/sql
I have these text:
${cat};${dog};
I would like to extract these:
${dog}
I'm trying with instr but allways shows me the last semicolon with these:
SELECT substr(field,instr(field,'$',1,2),instr(field,';',1,2)-1),...
Any help please

the function is defined as substr(str, pos, len), so you have to subtract the positions in the 3rd argument as substr(str, pos1, pos2 - pos1)

Not sure if it's what you need, but I would code this:
select substr('${cat};${dog};'
,instr('${cat};${dog};',';',1,1)+1
,instr('${cat};${dog};',';',1,2)-instr('${cat};${dog};',';',1,1)-1
)
from dual;

If looking for the second item in the list, here's a way using REGEXP_SUBSTR() to return the 2nd occurrence of a set of zero or more characters that are not a semi-colon, where they are followed by a semi-colon or the end of the line. This allows for a NULL value in the list:
select REGEXP_SUBSTR('${cat};${dog};', '([^;]*)(;|$)', 1, 2, NULL, 1) from dual;
Even better, make the call to REGEXP_SUBSTR generic and put it into a stored function that you pass a string, the element you want and the delimiter and have it return the string.
Benefits:
- Logic and code is encapsulated in a reusable function all can use without having to understand the regular expression syntax (but still get the power from it)
- There is a consistent, simple way to call it
- Code becomes MUCH easier to follow/debug
- If it needs to change there is only one place to change it
- A particular element of a list can be SELECTed
- An element of a list can be used in a WHERE clause
Here is the function definition itself:
FUNCTION GET_LIST_ELEMENT(string_in VARCHAR2, element_in NUMBER, delimiter_in VARCHAR2 DEFAULT ',') RETURN VARCHAR2 IS
BEGIN
RETURN REGEXP_SUBSTR(string_in, '([^\'||delimiter_in || ']*)(\'||delimiter_in||'|$)', 1, element_in, NULL, 1);
END GET_LIST_ELEMENT;

Related

expression is of wrong type for function

CREATE OR REPLACE FUNCTION k_w_b_salary(k IN NUMBER, b IN BOOLEAN)
RETURN EMP.ENAME%TYPE IS
names name_table;
BEGIN
IF (b = true) THEN
SELECT ENAME BULK COLLECT INTO names
FROM
(SELECT *
FROM EMP
ORDER BY SAL ASC)
WHERE ROWNUM <= k;
RETURN names;
ELSIF (b = false) THEN
SELECT ENAME BULK COLLECT INTO names
FROM
(SELECT *
FROM EMP
ORDER BY SAL DESC)
WHERE ROWNUM <= k;
RETURN names;
END IF;
END;
And I get this error:
12/9 PL/SQL: Statement ignored
12/16 PLS-00382: expression is of wrong type
20/9 PL/SQL: Statement ignored
20/16 PLS-00382: expression is of wrong type
I have this function that tries to find the best/worst paid employees. But i get the above error.
I think it's something to do with the ROWNUM but I am not sure.
I think the lines the error points out are not the lines with the error.
I had this function writen differently and the lines in the error where pointing to the ROWNUM <= k lines.
I have tried putting a fixed number there (<= 3) for example and I got the same error.
I have no idea what else to try, i can't really understand why this is not working.
It's not obvious to me why this is not working. I think it should work fine but obviously it dousen't.
The code for the table i use is :
CREATE OR REPLACE TYPE name_table IS TABLE OF VARCHAR2(10);
Any help is appreciated!
In the function declaration, you said
RETURN EMP.ENAME%TYPE
I assume the data type of column ENAME in table EMP is some sort of string (VARCHAR2(40) or similar) - right?
In the declarations section, you declare a variable names of data type name_table. You didn't show us the definition of the name_table type (that must be given outside the function, not in it); we can probably assume it is a nested table of some sort. Right? [EDIT - I take that back; you did show us your definition of name_table, at the end of your question.]
In the end, your function returns names. Which is of type name_table. But you said the function returns something else: EMP.ENAME%TYPE. In particular, you said the function returns a scalar data type, but you are returning a collection.
This will not work even if the collection has a single element. A table with a single "record" is not the same data type as the "record" itself - even if an actual table has a single "record" in it.
(And, much more so, when the table has three records in it!)
Rather: It seems that you want a table function: one that returns a table of things. If so, then declare the function that way. Perhaps you want the function to
RETURN NAME_TABLE
(at the top, in the function declaration)

PL/SQL Query for column and use it in the function call

I am trying this but sure I am missing a lot
declare
my_id table.ISR_ID%type;
begin
select NVL(MAX(table.ISR_ID)+1,1) into isr_id
from table;
select my_pkg.getFunction(InputToFunction=> isr_id); -- from ?
end;
If you declared MY_ID variable, you should have selected into it, not into ISR_ID (which is never declared).
Also, you should return function's result into something (probably another variable?). I've declared it as FUN_RES - see the comment within the PL/SQL anonymous block.
Saying that you are missing a lot doesn't help much; you should specify which errors you get. Anyway: try such a code, say whether it works or not and - if not - say why not (possible errors, etc.).
declare
my_id table.ISR_ID%type;
fun_res number; --> function result should be returned into this variable.
-- I don't know what it returns, so I set it to be a NUMBER.
-- Change it, if necessary.
begin
select NVL(MAX(table.ISR_ID) + 1, 1)
into my_id
from table;
fun_res := my_pkg.getFunction(my_id);
end;
[EDIT]
If you have to select function's value for every ISR_ID in a table, then you don't need PL/SQL but
select isr_id,
my_pkg.getfunction(isr_id) fun_res
from table;
If you want PL/SQL, then do it in a loop, for example:
begin
for cur_r in (select isr_id from table) loop
dbms_output.put_line(cur_r.isr_id ||', result = ' || my_pkg.getfunction(cur_r.isr_id));
end loop;
end;
/

REGEXP_SUBSTR return all matches (mariaDB)

I need to get all the matches of a regular expression in a text field in a MariaDB table. As far as I know REGEXP_SUBSTR is the way to go to get the value of the match of a regular expression in a text field, but it always returns after the first match and I would like to get all matches.
Is there any way to do this in MariaDB?
An example of the content of the text field would be:
#Generation {
// 1
True =>
`CP?:24658` <= `CPV?:24658=57186`;
//`CP?23432:24658` <= `CPV?:24658=57186`
// 2
`CP?:24658` <> `CPV?:24658=57178` =>
`CP?:24656` <> `CPV?:24656=57169`;
And the select expression that I'm using right now is:
select REGEXP_SUBSTR(textfield,'CP\\?(?:\\d*:)*24658') as my_match
from table
where id = 1243;
Which at the moment returns just the first match:
CP?:24658
And I would like it to return all matches:
CP?:24658
CP?23432:24658
CP?:24658
Use just REGEXP to find the interesting rows. Put those into a temp table
Repeatedly process the temp table -- but remove the SUBSTR as you use it.
What will you be doing with each substr? Maybe that will help us devise a better approach.

how do code a sql statement replacing all x'BF' with x'00' for a certain data field that contains the ascii downside ? to replace it with null x'00'

how do I code this properly to work in Oracle SQL :
update table_name
set field_name =
replace(field_name, x'BF', x'00')
where condition expression ;
Not sure how to code the replace all occurrence of hex 'BF' with null value hex'00' contained in data field field_name.
You can use the unistr() function to provide a Unicode character. e.g.:
update table_name
set field_name = replace(field_name, unistr('\00bf'))
where condition expression ;
which would remove the ¿ character completely; or to replace it with a null character:
set field_name = replace(field_name, unistr('\00bf'), unistr('\0000'))
though I suspect sticking a null in there will confuse things even more later, when some other system tries to read that text and stops at the null.
Quick demo:
with t (str) as (
select 'A ¿ char' from dual
)
select str,
replace(str, unistr('\00bf')) as removed,
replace(str, unistr('\00bf'), unistr('\0000')) as replaced,
dump(replace(str, unistr('\00bf')), 16) as removed_hex,
dump(replace(str, unistr('\00bf'), unistr('\0000')), 16) as replaced_hex
from t;
STR REMOVED REPLACED REMOVED_HEX REPLACED_HEX
--------- --------- --------- ----------------------------------- -----------------------------------
A ¿ char A char A char Typ=1 Len=7: 41,20,20,63,68,61,72 Typ=1 Len=8: 41,20,0,20,63,68,61,72
(Just as an example of the problems you'll have - because of the null I couldn't copy and paste that from SQL Developer, and had to switch to SQL*Plus...)
The first dump shows the two spaces (hex 20) next to each other; the second shows a null character between them.

How to fetch value between second and third / from string (/ to be consider from right to left)

My requirement is to fetch the data between second and third '/' from a string(/ to be consider from right to left) and below are sample examples.
1.My string is RAM/ESH/BA/BU/MOR/SA and output to be derived is BU
2.My string is RAM/ESH/BA/MOR/SA and output to be derived is BA
3.My String is TR/IV/NI and output to be derived is TR
Please help me query.
Here is one way to do it - using only standard string functions (no regular expressions) for best performance. Notice the use of INSTR with -1 as the third parameter (indicating position); negative means start AND count from the end of the string (from right to left).
I added two more input strings to test for correct handling. If there is absolutely nothing between the second and third / from the right, the "token" must be NULL. Same if there aren't at least two / in the input string. As I explained in a Comment, you misstated the problem - you need at least two slashes in the input; if there are only two, you are taking the "token" from the beginning of the input string.
with
inputs ( str ) as (
select 'RAM/ESH/BA/BU/MOR/SA' from dual union all
select 'RAM/ESH/BA/MOR/SA' from dual union all
select 'TR/IV/NI' from dual union all
select 'ST//TUL/SV' from dual union all
select 'MOR/SA' from dual
)
-- End of simulated inputs (for testing only, not part of the solution).
-- SQL query begins BELOW THIS LINE. Use your actual table and column names.
select str,
substr( str, instr(str, '/', -1, 3) + 1,
instr(str, '/', -1, 2) - instr(str, '/', -1, 3) - 1
) as third_token_from_right
from inputs;
STR THIRD_TOKEN_FROM_RIGHT
-------------------- ----------------------
RAM/ESH/BA/BU/MOR/SA BU
RAM/ESH/BA/MOR/SA BA
TR/IV/NI TR
ST//TUL/SV
MOR/SA

Resources