wrong number or types of arguments in call to my procedure - plsql

hi I wrote this code to create a procedure to return a Boolean value based on the if conditions but when I execute it I got this error:
ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'DDPAY_SP'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
here is my procedure
create or replace procedure DDPAY_SP (
donor_id dd_donor.iddonor%type,
pldgstatus out dd_pledge.idstatus%type,
monthplan out dd_pledge.paymonths%type,
ret out boolean)
IS
begin
select idstatus, paymonths into
pldgstatus, monthplan from dd_pledge
where iddonor = donor_id ;
if (pldgstatus = 10 AND monthplan >0)
then ret:= true;
else
ret:= false;
end if;
end;
and this how I execute it
EXECUTE DDPAY_SP (308);
I didn't put much talk I hope it's clear enough for you
I read online it recommends me to check the naming also the data type which I did but nothing change
any ideas

If you don't need the second and third arguments you could declare those as variables in the procedure instead of arguments, as follows:
CREATE OR REPLACE PROCEDURE DDPAY_SP(DONOR_ID IN DD_DONOR.IDDONOR%TYPE,
RET OUT BOOLEAN)
IS
nPayment_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO nPayment_count
FROM DD_PLEDGE p
WHERE p.IDDONOR = DONOR_ID AND
p.IDSTATUS = 10 AND
p.PAYMONTHS > 0;
IF nPayment_count > 0 THEN
RET := TRUE;
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('DD_PAY - exception: ' || SQLCODE || ' : ' || SQLERRM);
RAISE;
END DDPAY_SP;
I've included an example of an EXCEPTION handler at the end of DD_PAY. It's always a good idea to include at least this minimal handler so that in the event an exception occurs you'll get some indication of where the problem lies.
Because this procedure returns a BOOLEAN value, and BOOLEANs cannot (to the best of my knowledge) be used from SQL*Plus, you'll have to invoke it from a PL/SQL block, as follows:
DECLARE
bRetval BOOLEAN;
BEGIN
DD_PAY(308, bRetval);
DBMS_OUTPUT.PUT_LINE('Returned value is ' ||
CASE bRetval
WHEN TRUE THEN 'TRUE'
ELSE 'FALSE'
END);
END;
Give that a try.
EDIT: rewrote procedure based on further information from later comments.
Share and enjoy.

Related

Oracle APEX: Execute immediate on collection

I have the following code:
declare
y pls_integer := 0;
v_msg varchar2(4000);
plsql varchar(4000);
begin
if not apex_collection.collection_exists(p_collection_name=>'P16_COLLECTION') then
wwv_flow.debug('No Apex collection found!');
else
for x in (select * from apex_collections where collection_name = 'P16_COLLECTION' and seq_id > 1 order by seq_id)
loop
y := y+1;
FOR i IN 1..25
LOOP
plsql := 'begin apex_collection.update_member_attribute (p_collection_name=> ''P16_COLLECTION'', p_seq=>' || TO_CHAR(x.seq_id) || ',p_attr_number =>' || TO_CHAR(i) || ',p_attr_value=>wwv_flow.g_f' || TO_CHAR(i, 'FM00') || '(' || TO_CHAR(y) || ')); end;';
wwv_flow.debug(plsql);
EXECUTE IMMEDIATE plsql;
END LOOP;
end loop;
end if;
exception when others then
v_msg := ''||sqlerrm;
wwv_flow.debug('ERR: '||v_msg);
end;
This code is very similar to the one proposed here, but I loop through 25 columns. The issue with Oracle Apex is the max number of chars PL/SQL is allowed to have, so I am unable to just write 25 update_member_attribute - calls.
But instead of a it excecuting I get an error no data found.
I triple checked that the collection P16_COLLECTION exists.
The issue with Oracle Apex is the max number of chars PL/SQL is allowed to have
I'm not sure I understood this statement. It is PL/SQL you use. You declared a local PLSQL variable as VARCHAR2(4000). Why didn't you specify its max allowed size, 32767? Would that help?
Furthermore, saying that you got NO-DATA-FOUND exception: are you sure that this piece of code raised it? Because, there's no SELECT statement in there ... the one you used in a cursor FOR loop can't raise NO-DATA-FOUND; UPDATE either. Therefore, it must be something else, I presume.
Enable DEBUG, run the page and - when you get the error - view debug results and locate the culprit.

Oracle PL/SQL - ORA-01403 “No data found” when using “SELECT INTO”

I have a pl sql code that execute three queries sequentially to determine a match level and do some logic
The issue is - when first query has no results (completely valid scenario) I get ORA-01403 No data found.
I understand that I need to incorporate [ Exception clause when NO_DATA_FOUND ]- but how to add it and continue to the next query?
PL/SQL Code
SELECT A into PARAM A FROM SAMPLE WHERE SOME CONDITION;
-- GOT ORA-01403 No data found HERE
MATCH_LEVEL =1;
if A is null then
do some logic;
end if
SELECT A INTO PARAM_B FROM SAMPLE WHERE SOME OTHER CONDITION
MATCH_LEVEL =2
if A is null then
do some logic 2;
end if
SELECT A INTO PARAM_B FROM SAMPLE WHERE SOME OTHER CONDITION
MATCH_LEVEL =3
if A is null then
do some logic 3;
end if
END PL/SQL Code
Declare
--your declarations
begin
SELECT A into PARAM A FROM SAMPLE WHERE SOME CONDITION;
-- GOT ORA-01403 No data found HERE
Begin
MATCH_LEVEL =1;
if A is null then
do some logic;
end if;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line ('Error...');
END;
--- and son on for other blocks
end;
Just surround your SELECT INTO with begin-end;
begin
-- your faulty statement here
Exception
When NO_DATA_FOUND Then
-- Do what you want or nothing
WHEN TOO_MANY_ROWS THEN
-- what if you get more then one row? and need specific handler for this
When OTHERS Then
-- do something here or nothing (optional - may happen if you have more than your SELECT INTO between 'begin' and 'Exception')
end;
This is like try block of PL/Sql
With this technique you can log the reason your statement failed.
For a SELECT ... INTO ... statement, the PL/SQL engine assume there will be one, and only one row returned by your query. If there is no row, or more than one, an exception is raised.
FWIW, you can handle such cases without resorting on exception handling by using aggregate functions. That way, there will always be only one row in the result set.
Assuming A can't be NULL in your rows:
SELECT MAX(A) into PARAM A FROM SAMPLE WHERE SOME CONDITION;
-- A would be NULL if there was *no* row. Otherwise, it is *the* value for *the* row
MATCH_LEVEL =1;
if A is null then
do some logic;
end if
If the NULL value is a possible case, just add an extra COUNT(*) column:
SELECT MAX(A), COUNT(*) into A, HAS_FOUND_ROW FROM SAMPLE WHERE SOME CONDITION;
if HAS_FOUND_ROW > 0 then
...
end if;
Oracle will not allow you to open an implicit cursor (i.e. a select statement in the body of a code block) that returns no rows. You have two options here (3 really, counting #Sylvain's answer, but that is an unusual approach): use an explicit cursor or handle the error.
Explicit Cursor
An explicit cursor is one found in the DECLARE section it must be opened and fetched manually (or in a FOR loop). This has the added advantage that, if you parameterize the query properly, you can write it once and use it multiple times.
DECLARE
a sample.a%type;
MATCH_LEVEL number;
cursor cur_params (some_column_value number) is
SELECT A FROM SAMPLE WHERE some_column = some_column_value;
BEGIN
MATCH_LEVEL := 1;
open cur_params (match_level);
fetch cur_params into a;
close cur_params;
if A is null then
null; --some logic goes here
end if;
MATCH_LEVEL := 2;
open cur_params (match_level);
fetch cur_params into a;
close cur_params;
if A is null then
null; --some logic goes here
end if;
end;
Handle the error
If you choose to handle the error, you'll need to create a BEGIN...END block around the code that is going to throw the error. When disregarding an error, it's crucial that you ensure that you are only disregarding the specific error you want avoid, when generated from the specific statement you expect it from. If you simply add the EXCEPTION section to your existing BEGIN...END block, for instance, you couldn't know which statement generated it, or even if it was really the error you expected.
DECLARE
a sample.a%type;
MATCH_LEVEL number;
BEGIN
MATCH_LEVEL := 1;
BEGIN
SELECT A into A FROM SAMPLE WHERE some_column = MATCH_LEVEL;
EXCEPTION
WHEN NO_DATA_FOUND THEN
null; --Do nothing
END;
if A is null then
null; --some logic goes here
end if;
MATCH_LEVEL := 2;
BEGIN
SELECT A into A FROM SAMPLE WHERE some_column = MATCH_LEVEL;
EXCEPTION
WHEN NO_DATA_FOUND THEN
null; --Do nothing
END;
if A is null then
null; --some logic goes here
end if;
end;
While I'd discourage it, you can catch any other errors in the same exception blocks. However, by definition, those errors would be unexpected, so it would be a poor practice to discard them (you'll never know they even happened!). Generally speaking, if you use a WHEN OTHERS clause in your exception handling, that clause should always conclude with RAISE;, so that the error gets passed up to the next level and is not lost.

"Identifier must be declared" when using a function

I have the following function in a package body:
FUNCTION valida_salario(p_salary IN employees.salary%TYPE,
p_department_id IN employees.department_id%TYPE)
RETURN BOOLEAN IS
v_prom_depto NUMBER;
v_var_depto NUMBER;
BEGIN
SELECT AVG(salary), VARIANCE(SALARY) INTO v_prom_depto, v_var_depto
FROM employees
WHERE department_id=p_department_id;
-- GROUP BY department_id;
IF p_salary < v_prom_depto + 3* sqrt(v_var_depto) THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
END valida_salario;
And when I am using the function in a stored procedure (the procedure is in the body too), it show errors:
PROCEDURE crea_empleado(p_last_name IN employees.last_name%TYPE,
p_first_name IN employees.first_name%TYPE,
p_email IN employees.email%TYPE,
p_hire_date IN employees.hire_date%TYPE,
p_job_id IN employees.job_id%TYPE,
p_department_id IN employees.department_id%TYPE
DEFAULT 80,
p_resultado OUT NUMBER) AS
e_salario_no_valido EXCEPTION;
BEGIN
IF valida_salario(p_salary, p_department_id) THEN // Here is located the errors
NULL;
ELSE
RAISE e_salario_no_valido;
END IF;
INSERT INTO employees(employee_id, last_name, first_name, email, hire_date, job_id)
VALUES (emp_seq.NEXTVAL, p_last_name, p_first_name, p_email, p_hire_date, p_job_id);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
p_resultado := 2;
dbms_output.put_line('Datos duplicados');
WHEN e_salario_no_valido THEN
p_resultado := 1;
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
ROLLBACK;
END crea_empleado;
The following errors are :
PL/SQL: Statement ignored and
PLS-00201: the identifier 'P_SALARY' must be declared
But I can't see the error in my function, so I don't understand why it shows these errors.
Thanks in advance for your help
You need to pass p_salary into your crea_empleado() procedure. p_department_id is there but no p_salary.

Simple PL/SQL function to test if a string is a number

I'm experienced with T-SQL from SQL Server, but have recently begun working on a project utilizing an Oracle database (11g) and am having some issues writing what seems to be basic code.
I need to test whether a set of values are numeric, and only insert them into a table if they are. PL/SQL doesn't seem to have an is_number function, so I wrote my own based on an AskTom question.
create or replace
function IS_NUMBER(str in varchar2) return boolean
IS
n number;
BEGIN
select to_number(str) into n from dual;
return (true);
EXCEPTION WHEN OTHERS THEN
return (false);
END;
Eventually, I'd like to use this function in a WHERE clause, but for now I'm just trying to get it to run at all:
declare
str varchar2(1);
n boolean;
begin
str := '0';
select ca_stage.is_number(str) into n from dual;
end;
In SQL Developer, trying to run this gives me the following error report:
Error report:
ORA-06550: line 6, column 39:
PLS-00382: expression is of wrong type
ORA-06550: line 6, column 19:
PLS-00382: expression is of wrong type
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
The error report is straight-forward, but doesn't make sense. The function accepts a varchar2, and that's what I'm using as an input variable. It returns a boolean and again, that's what I'm using.
As I said, this is basic code, so I assume that I'm missing something fundamental.
Return a SQL datatype, e.g. VARCHAR2. Also, I'd recommend against using WHEN OTHERS. Also, you don't need a query on dual:
create or replace
function IS_NUMBER(str in varchar2) return varchar2
IS
n number;
BEGIN
n := to_number(str);
return 'Y';
EXCEPTION WHEN VALUE_ERROR THEN
return 'N';
END;

Check a record IS NOT NULL in plsql

I have a function which would return a record with type my_table%ROWTYPE, and in the caller, I could check if the returned record is null, but PL/SQL complains the if-statement that
PLS-00306: wrong number or types of arguments in call to 'IS NOT NULL'
Here is my code:
v_record my_table%ROWTYPE;
v_row_id my_table.row_id%TYPE := 123456;
begin
v_record := myfunction(v_row_id)
if (v_record is not null) then
-- do something
end if;
end;
function myfunction(p_row_id in my_table.row_id%TYPE) return my_table%ROWTYPE is
v_record_out my_table%ROWTYPE := null;
begin
select * into v_record_out from my_table
where row_id = p_row_id;
return v_record_out;
end myfunction;
Thanks.
As far as I know, it's not possible. Checking the PRIMARY KEY or a NOT NULL column should be sufficient though.
You can check for v_record.row_id IS NULL.
Your function would throw a NO_DATA_FOUND exception though, when no record is found.
You can't test for the non-existence of this variable so there are two ways to go about it. Check for the existence of a single element. I don't like this as it means if anything changes your code no longer works. Instead why not just raise an exception when there's no data there:
I realise that the others in the exception is highly naughty but it'll only really catch my table disappearing when it shouldn't and nothing else.
v_record my_table%ROWTYPE;
v_row_id my_table.row_id%TYPE := 123456;
begin
v_record := myfunction(v_row_id)
exception when others then
-- do something
end;
function myfunction(p_row_id in my_table.row_id%TYPE) return my_table%ROWTYPE is
v_record_out my_table%ROWTYPE := null;
cursor c_record_out(c_row_id char) is
select *
from my_table
where row_id = p_row_id;
begin
open c_record_out(p_row_id);
fetch c_record_out into v_record_out;
if c_record_out%NOTFOUND then
raise_application_error(-20001,'no data);
end if;
close c_record_out;
return v_record_out;
end myfunction;

Resources