call function from sql script in oracle - oracle

In this code I am calling this FSG.REPLACE_STRING function which has 2 parameters, original string and special characters string. The original string is a select query from a table and special character string is 'A'.
I have written the code:
FSG.REPLACE_STRING ( (SELECT CAST(NVL(PRAD_ID , ' ') AS CHAR(12))
FROM FSG_WRK.FSG_PRCB_AUXDB_PRAD WHERE PRAD_ID= '003204091007'), A );
but this is not working.

You are trying to pass the table column value into the function, so you need to restructure your statement:
SELECT FSG.REPLACE_STRING (CAST(NVL(PRAD_ID, ' ') AS CHAR(12)), 'A')
FROM FSG_WRK.FSG_PRCB_AUXDB_PRAD
WHERE PRAD_ID= '003204091007';
Although the NVL() part seems a bit pointless if you're filtering for a specific (not-null) value in the query. Casting to char looks suspicious too.

Related

Oracle change string to decimal

I need to convert string to decimals.
So the string value is: 89,333,22.2345
So i want to keep all decimal places and convert it to: 8933322.2345.
I tried the following query:
select to_number(replace(nvl(89,333,22.2345),0),',','') from dual;
This rounds it to 893322. But i want result with all decimals:
If i try running this query:
select to_number((replace(nvl(89,333,22.2345),0),',',''),'9999.99') from dual;
it throws error.
Try this:
select to_number('89,333,22.2345','99,999,99.9999') from dual;
I think you're passing the number as a parameter. Otherwise why would you use nvl. Then I see the query you need is going to be similar like that
select to_number(replace(nvl('89,333,22.2345','0'),',','')) from dual;
Things were wrong at your code:
since number is a varchar, it has to be placed between apostrophes
nvl takes parameters divided by a comma. And there was one closing bracket too much
nvl(89,333,22.2345),0) -> nvl('89,333,22.2345',0)

ORA-00936 with a substitution variable - error does not make sense

A super simple example of my script looks as follows:
-- Report Name: "Report_1"
col letters new_value p_letters
SELECT letters
FROM param_table
WHERE report_name = 'Report_1';
CREATE TABLE temp_table_1
(letter varchar2(1));
INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE '&&p_letters' = '' OR letter IN (&&p_letters);
For some reason, our system has a table called param_table: users enter parameters through the UI, the parameters entered are written to param_table, and then my script pulls the user's parameters from param_table.
As far as I understand, the first SELECT statement selects the letters column from param_table and makes its values accessible in '&&p_letters'. In my INSERT INTO statement, when my WHERE clause looks like this...
WHERE letter IN (&&p_letters);
...and the user enters letters separated by single quotes, eg ('A', B', C'), the script runs fine. I want to make the parameter optional, so I adjusted the WHERE clause like this:
WHERE '&&p_letters' = '' OR letter IN (&&p_letters);
In my output file, I get the following error:
WHERE (('' = '') OR letter IN ()) *
ERROR at line ...:
ORA-00936: missing expression
The compiler has evaluated the substitution variable correctly as '', but I'm getting an error.
Any idea what I could be doing wrong here?
The ORA-00936 is because IN () is not valid - you're missing something inside that. It is that it is complaining about, not the '' = '' part, though the result of that is undefined. You can check both conditions:
SQL> select * from dual where '' = '';
no rows selected
SQL> select * from dual where dummy in ();
select * from dual where dummy in ()
*
ERROR at line 1:
ORA-00936: missing expression
If you set verify on you can see how the substitution is handled. For your original query you'd see:
old:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE letter IN (&&p_letters)
new:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE letter IN ('A','B','C')
3 rows inserted.
You can see that the post-substitution statement looks, and is, valid.
With your modified query you'd see:
old:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE '&&p_letters' = '' OR letter IN (&&p_letters)
new:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE ''A','B','C'' = '' OR letter IN ('A','B','C')
which generates an ORA-00920 because of the messed-up single quotes in the first expression. With no value from letters you'd instead see:
old:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE '&&p_letters' = '' OR letter IN (&&p_letters)
new:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE '' = '' OR letter IN ()
which is the error you saw, ORA-00936.
I'd be tempted to do this with a collection type, either your own, or if you're comfortable with it then a built-in one:
INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE SYS.DBMS_DEBUG_VC2COLL(&&p_letters) IS EMPTY
OR letter MEMBER OF SYS.DBMS_DEBUG_VC2COLL(&&p_letters);
That works with your three comma-separated values, or null, since an empty collection is allowed. Read more about is empty and member of.
It would be better, of course, to not store comma-separated lists in a single column value anyway, and to change your data model so this kind of manipulation and reliance on client behaviour isn't necessary.
Assuming you're stuck with the data model, you could at least avoid the client reliance buy tokenizing the string (I'm using one common approach below) and looking for matches. However, you also need to account for either the report name not being in the table at all or the report existing with no letters value, both of which are handled by the max(letters) .. is null check - which makes it a bit ugly.
It's all in one statement though, with no need for a separate query to get the parameters and no need for substitution variables. (And there may be better ways to do it!)
INSERT INTO temp_table_1 (letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE (
SELECT MAX(letters)
FROM param_table
WHERE report_name = 'Report_2'
) IS NULL
OR letter IN (
SELECT TRIM(q'[']' FROM REGEXP_SUBSTR(letters, '[^,]', 1, LEVEL))
FROM param_table
WHERE report_name = 'Report_2'
CONNECT BY REGEXP_SUBSTR(letters, '[^,]', 1, level) IS NOT NULL
);

REGEXP_SUBSTR for portion of string

I would like to get:
82961_01B04WZXQQSUGJ4YMRRT2A7TRHK_MR_2_1of1
from the following expression
LASTNAME_FIRSTNAME_82961_01B04WZXQQSUGJ4YMRRT2A7TRHK_MR_2_1of1
Does someone know how I can get this using regexp_substr ?
EDIT
Basically I have a field which has 7 sets each separated by _ . The string I gave is just one example. I wanted to retrieve everything after the second _ . There is no fixed character length so I can not use a substr function. Hence I was using regexp_substr. I was able to get away by using a simplified version
Select FILE_NAME, ( (REGEXP_SUBSTR(FILE_NAME,'[^_]+_',1,3)) ||
(REGEXP_SUBSTR(FILE_NAME,'[^_]+_',1,4)) ||
(REGEXP_SUBSTR(FILE_NAME,'[^_]+_',1,5)) ||
(REGEXP_SUBSTR(FILE_NAME,'[^_]+_',1,6)) ||
(REGEXP_SUBSTR(FILE_NAME,'[^_]+',1,7)) ) as RegExp
from tbl
Here is some more data from the FILE_NAME field
LAST_FIRST_82961_01B04WZXQQSUGJ4YMRRT2A7TRHK_MR_2_1of1
SMITH_JOHN_82961_0130BPQX9QZN9G4P5RDTPA9HR4R_MR_1_1of1
LASTNAME_FIRSTNAME_99999_01V0MU4XUQK0Y24Y9RYTFA7W1CM_MR_3_1of1
To get everything after the second underscore, you do not need regular expressions, but can use something like the following:
select substr(FILE_NAME, instr(FILE_NAME, '_', 1, 2) +1 ) from tbl
The instr returns the position of the second occurrence of '_', starting by the first character; the substr simply gets everything starting from the position given by instr + 1
From your Requirement, you can just go ahead and use the simple SUBSTRfunction. Its faster, and it addresses the simple need to remove the String LASTNAME_FIRSTNAME.
select substr('LASTNAME_FIRSTNAME_82961_01B04WZXQQSUGJ4YMRRT2A7TRHK_MR_2_1of1', 20) data_string
from dual;
Output:
data_string
-----------------
82961_01B04WZXQQSUGJ4YMRRT2A7TRHK_MR_2_1of1
Unless you have another underlying logic you need to address?
Kindly clarify so i can edit the answer accordingly.

To insert a value in a String

I have a requirement to manipulate a string to get the required value.
I need to change ACTUALSTRING99 to ACTUALSTRING_99. Currently I am passing this ACTUALSTRING99 to a function and returning it as ACTUALSTRING_99 in the following way.
SELECT 'VALUE' AS ACTUAL,
REGEXP_REPLACE('VALUE', '[[:digit:]]') AS STRING,
REGEXP_REPLACE('VALUE', '[[:alpha:]]') AS DIGIT,
concat(concat(REGEXP_REPLACE('VALUE', '[[:digit:]]'),'_'),REGEXP_REPLACE('VALUE', '[[:alpha:]]')) AS REQUIRED
FROM dual;
Passing VALUE asACTUALSTRING99. Do we have any other simple way (using or without using regular expression) to do it with out calling the function?
To prepend underscore before numerical part of the string, you can simply use regexp_replace with backreference.
SELECT
REGEXP_REPLACE('actualstring99','([[:digit:]]+)','_\1')
FROM dual;
You can do this using substring and length functions:
SELECT SUBSTR('VALUE',0,LENGTH('VALUE')-2) || '_' ||
SUBSTR('VALUE',LENGTH('VALUE')-2,LENGTH('VALUE'))
FROM dual;

Is it possible to join strings in PL/SQL procedure in my sql statement

As the title suggests, I would like to know if it is possible to join the string in a select statement within a PL/SQL procedure.
For example, I have something like this
SELECT FCS.CATEGORY,
FCS.NUMBERS,
FCS.POINTS
WHERE FCS.OBJECT = 'T'
AND FCS.THIS_DB & strSelectedDB &
So, is it possible to do something like this?
Your example is a little confusing. You can concatenate multiple strings using the || operator. But you'd then you'd have to compare the concatenated string to something. You can compare columns to local variables directly, though, i.e.
SELECT fcs.category,
fcs.numbers,
fcs.points
FROM some_table fcs
WHERE fcs.object = 'T'
AND fcs.this_db = strSelectedDB
assuming that strSelectedDB is a local variable in your PL/SQL block.

Resources