PLS-00049: bad bind variable ' while creating procedure - oracle

Hi I'm trying to create a procedure for which the code is given below:
CREATE PROCEDURE profit_calcs(profit OUT NUMBER,
em IN NUMBER,
eq IN NUMBER,
p IN NUMBER,
u IN NUMBER,
income IN NUMBER,
ex IN NUMBER) AS
BEGIN
SELECT SUM(amount) INTO em FROM a_em;
SELECT SUM(amount) INTO eq FROM a_eq;
SELECT SUM(amount) INTO p FROM a_p;
SELECT SUM(amount) INTO u FROM a_u;
SELECT SUM(amount) INTO income FROM sales;
ex := :em + :eq + :p + :u;
profit := :income - :ex;
END;
/
whenever I'm trying to create it I'm getting the following error:
LINE/COL ERROR
--------- -------------------------------------------------------------
10/7 PLS-00049: bad bind variable 'EM'
10/13 PLS-00049: bad bind variable 'EQ'
10/18 PLS-00049: bad bind variable 'P'
10/22 PLS-00049: bad bind variable 'U'
11/11 PLS-00049: bad bind variable 'INCOME'
11/21 PLS-00049: bad bind variable 'EX'
It will be very helpful if someone helps me to solve this error.

Because, you need to define those variables at the declaration section just after the keyword AS, before BEGIN such as
CREATE OR REPLACE PROCEDURE profit_calcs(profit OUT NUMBER,
ex OUT NUMBER) AS
em INT;
eq INT;
p INT;
u INT;
income INT;
BEGIN
or convert them to OUT type parameters for this stored procedure such as
CREATE OR REPLACE PROCEDURE profit_calcs(profit OUT NUMBER,
em OUT NUMBER,
eq OUT NUMBER,
p OUT NUMBER,
u OUT NUMBER,
income OUT NUMBER,
ex OUT NUMBER) AS
BEGIN
where
don't forget to remove colons prefixing those variables such as
:em,:eq should be em,eq respectively
REPLACE option for CREATE PROCEDURE command shouldn't be omitted
considering the upcoming compilations

Related

inserting into relational table from entity table

Hi I want to create a trigger which will insert values on relational table A_EQ, A_U and A_P after inserting the values to entity table ACCOUNTS. The values will the inserted into A_EQ if only the ACCOUNTS.TYPE='Equipments', into A_U if only ACCOUNTS.TYPE='Utility' and into A_P for the rest.
Whenever I'm trying to compile the trigger certain errors are showing:
Error(40,13): PLS-00049: bad bind variable 'NEW.A_U'
Error(41,13): PLS-00049: bad bind variable 'NEW.A_U'
Error(42,13): PLS-00049: bad bind variable 'NEW.A_U'
Error(45,9): PLS-00049: bad bind variable 'NEW.A_EQ'
Error(46,13): PLS-00049: bad bind variable 'NEW.A_EQ'
Error(47,13): PLS-00049: bad bind variable 'NEW.A_EQ'
Error(50,9): PLS-00049: bad bind variable 'NEW.A_P'
Error(51,13): PLS-00049: bad bind variable 'NEW.A_P'
Error(52,13): PLS-00049: bad bind variable 'NEW.A_P'
Error(57,4): PLS-00103: Encountered the symbol ";" when expecting one of the following: if
The Code for trigger is given below:
create or replace trigger accounts_relational_insert
after insert on accounts
REFERENCING NEW AS new OLD AS Old
for each row
declare
sys_month VARCHAR2 (10) ;
i_month VARCHAR2 (10);
old1 int;
curr_amount number (20,2);
curr_id varchar2 (20);
curr_txn varchar2 (20);
curr_type varchar2 (20);
begin
select to_char(SYSDATE,'Month') into sys_month from dual;
select ACCOUNTS_ID_SEQ.currval into old1 from dual;
select to_char(paid_on,'Month') into i_month from accounts where transaction_id ='Txn' || lpad(old1,9,'0');
select amount into curr_amount from accounts where transaction_id='Txn' || lpad(old1,9,'0');
select id into curr_id from accounts where transaction_id='Txn' || lpad(old1,9,'0');
select transaction_id into curr_txn from accounts where transaction_id='Txn' || lpad(old1,9,'0');
select type into curr_type from accounts where transaction_id='Txn' || lpad(old1,9,'0');
if i_month = sys_month then
if curr_type ='Utility' then
:new.a_u.transaction_id := curr_txn;
:new.a_u.u_id :=curr_id;
:new.a_u.amount := curr_amount;
else if curr_type='Equipments' then
:new.a_eq.transaction_id := curr_txn;
:new.a_eq.eq_id :=curr_id;
:new.a_eq.amount := curr_amount;
else
:new.a_p.transaction_id := curr_txn;
:new.a_p.barcode:=curr_id;
:new.a_p.amount := curr_amount;
end if;
end if;
end;
The Tables are given below:
It will be very helpful if someone tells me how to resolve this error and also if there is any other way to insert into relational tables after inserting on accounts table.
You can rearrange the trigger simply as simple as this one
CREATE OR REPLACE TRIGGER accounts_relational_insert
AFTER INSERT ON accounts
FOR EACH ROW
BEGIN
IF TO_CHAR(:new.paid_on, 'YYYYMM') = TO_CHAR(sysdate, 'YYYYMM') THEN
IF :new.type = 'Utility' THEN
INSERT INTO a_u VALUES(:new.id, :new.transaction_id, :new.amount);
ELSIF :new.type = 'Equipments' THEN
INSERT INTO a_eq VALUES(:new.id, :new.transaction_id, :new.amount);
ELSE
INSERT INTO a_p VALUES(:new.id, :new.transaction_id, :new.amount);
END IF;
END IF;
END;
/
where
the values, which are already been able to get from identifiers of
columns of the table accounts qualified with :new , to be
inserted shouldn't return from SELECT statements. Moreover, you would get mutating
trigger error for this case.
indeed, defining the local variables are not needed due to the fact
that expressed above, and also values for i_month and sys_month
will directly be derived from TO_CHAR(:new.paid_on, 'YYYYMM') and
TO_CHAR(sysdate, 'YYYYMM') respectively. Btw, do not prefer using string
expression within character conversion such as Month, since you might not
only face case sensitivity issues, but also might fail for international
studies related to language differences.
the trigger is created on accounts table, for the other tables you
should use INSERT statements, cannot use such variable assignments.
The expression REFERENCING NEW AS new OLD AS old is redundant, as
being default.

Oracle function to return value from select with union

I am trying to add this function to oracle db but it keeps throwing the following errors:
10/72 PLS-00049: bad bind variable 'COMMITID'
12/90 PLS-00049: bad bind variable 'COMMITID'
14/76 PLS-00049: bad bind variable 'COMMITID'
17/16 PL/SQL: ORA-00933: SQL command not properly ended
CREATE OR REPLACE FUNCTION GetLatestProfileChangeDateTime(commitId IN NUMBER)
RETURN DATE
AS
testing DATE;
BEGIN
select max(a) as dateOfChange
INTO testing
from
(
select max(created_date) a from image_set where reference_id = :commitId and created_date is not null
union
select max(date_of_change) a from preferred_agent_info_history where commit_id = :commitId and date_of_change is not null
union
select max(date_of_change) a from commit_history where commit_id = :commitId and date_of_change is not null
)
RETURN testing;
END;
The inner select statement works fine but when I try to implement it within a function, I can't get it to accept it. I've even tried removing the parameter binding in the select statements for a starting place but it will throw different errors.
You don't need bind variables in your function; you are using the function parameter in the SQL part of the function, so you can simply refer to it by its name.
For example:
SQL> create or replace function f1(p IN number) return number is
2 retVal number;
3 begin
4 select :p * 2 into retVal from dual;
5 return retVal;
6 end;
7 /
Warning: Function created with compilation errors.
SQL> sho err
Errors for FUNCTION F1:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/12 PLS-00049: bad bind variable 'P'
The right way:
SQL> create or replace function f1(p IN number) return number is
2 retVal number;
3 begin
4 select f1.p * 2 into retVal from dual;
5 return retVal;
6 end;
7 /
Function created.
SQL> select f1(3) from dual;
F1(3)
----------
6

How to escape a round bracket '(' in SQL?

I am trying to use reference cursor for a sql query but I think I am missing >escape notation somewhere. I have already escaped " ' " but I am unsure about >the round brackets.
I am getting "international_flag : invalid identifier" error at open ref_cursor statement. I have tried a bunch of things to escape round brackets because I think that is why it is not picking the variable international_flag. Any leads will be much appreciated.
declare
international_flag varchar2(4) := 'Y';
term_code varchar(8) := '201709';
type stu_ref_cursor is ref cursor;
ref_cursor stu_ref_cursor;
ref_cursor_select_statement varchar2(1000);
begin
ref_cursor_select_statement :=
'Select
CONFID_MSG,
ETHNIC_CODE,
STUDENT_NAME,
POTSDAM_ID(STUDENT_PIDM),
CLASS,
LEVL_CODE,
AGE,
BIRTHDATE,
fp_get_coll_box(STUDENT_PIDM),
f_get_on_campus_email_addr(STUDENT_PIDM),
RESD_IND,
STUDENT_PIDM,
REG_HRS,
SGB_TERM_ADMIT,
GENDER
From SEM_REG_STUDENT_NONGPA
Where REG_TERM = term_code
And STATUS = ''AS''
And REG_TERM_STATUS = ''Y''
And
(
international_flag = ''N''
Or
(international_flag = ''Y'' And f_international_student_natn(STUDENT_PIDM) Is Not NULL)
Or
(international_flag = ''U'' and CITIZEN = ''Y'')
)
Order By STUDENT_NAME';
open ref_cursor for ref_cursor_select_statement;
end;
That isn't how you reference PL/SQL variables in dynamic SQL. You need to use placeholders prefixed by a colon, and supply the variable with the USING clause. That can mean repetition where, as in this case, you use the same variable several times. You'll need to put in three placeholders and pass in the same variable three times (ie USING international_flag,international_flag,international_flag)
DECLARE
TYPE EmpCurTyp IS REF CURSOR; -- define weak REF CURSOR type
emp_cv EmpCurTyp; -- declare cursor variable
my_ename VARCHAR2(15);
my_sal NUMBER := 1000;
BEGIN
OPEN emp_cv FOR -- open cursor variable
'SELECT ename, sal FROM emp WHERE sal > :s' USING my_sal;
...
END;
PS. It is better to prefix variables (often with a v_ but some people go fo l_ for local and g_ for global etc) to make it more obvious what is a column and what is a variable.
The beauty of dynamic sql is that you never get to know the error as it gives run time error only. The binding of variables should be check properly before constructing a dynamic sql. Here there are two variables like "TERM_CODE" and "INTERNTIONAL_FLAG". Hope the below snippet helps.
DECLARE
international_flag VARCHAR2(4) := 'Y';
TERM_CODE VARCHAR(8) := '201709';
ref_cursor sys_refcursor;
ref_cursor_select_statement VARCHAR2(1000);
BEGIN
ref_cursor_select_statement := 'Select
CONFID_MSG,
ETHNIC_CODE,
STUDENT_NAME,
POTSDAM_ID(STUDENT_PIDM),
CLASS,
LEVL_CODE,
AGE,
BIRTHDATE,
fp_get_coll_box(STUDENT_PIDM),
f_get_on_campus_email_addr(STUDENT_PIDM),
RESD_IND,
STUDENT_PIDM,
REG_HRS,
SGB_TERM_ADMIT,
GENDER
From SEM_REG_STUDENT_NONGPA
Where REG_TERM = '''||term_code||'''
And STATUS = ''AS''
And REG_TERM_STATUS = ''Y''
And
('''|| international_flag||''' = ''N''
Or
('''||international_flag||''' = ''Y'' And f_international_student_natn(STUDENT_PIDM) Is Not NULL)
Or
('||
international_flag||' = ''U'' and CITIZEN = ''Y'')
)
Order By STUDENT_NAME';
OPEN ref_cursor FOR ref_cursor_select_statement;
END;
/

Variable in UPDATE oracle in procedure : invalid identifier

I don't understand why service is complaining with
Fehler(36,11): PL/SQL: ORA-00904: "FOUND_VP": invalid identifier
Variable is declared in the first begin...
Is it not possible to use variable directly in queries ?
when trying store following procedure :
create or replace PROCEDURE fpwl_update_vp(
my_zn IN NUMBER, my_verwaltung IN VARCHAR2 , my_variante IN NUMBER, my_vp IN NUMBER
) IS
BEGIN
DECLARE
search_VP IFT_INFO_LAUF.VP%TYPE;
found_VP IFT_INFO_LAUF.VP%TYPE;
INFOversion number := 25;
BEGIN -- search SYFA_VP
SELECT SYFA_VP
INTO found_VP
FROM FPWL_VP_MAPPING
WHERE INFO_VP=search_VP ;
exception
when no_data_found then
dbms_output.put_line ('Kein SYFA VP : Importiere aus SYFA');
--found_VP:=:=cus_info25.pa_info_data.fn_insert_syfa_vp(my_vp,25);
WHEN OTHERS THEN
ROLLBACK;
RETURN;
END; -- SYFA VP
-- Update VP
UPDATE IFT_INFO_LAUF
SET vp = found_VP
WHERE id_kopf IN
(SELECT id_kopf
FROM ift_info_kopf
WHERE fahrtnummer= my_zn
AND verwaltung= my_verwaltung
AND variante = my_variante
)
;
--COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END ;
Your problem is that found_VP is going out of scope.
Move the contents of the "DECLARE" block to just after the "IS":
create or replace PROCEDURE fpwl_update_vp(
my_zn IN NUMBER, my_verwaltung IN VARCHAR2 , my_variante IN NUMBER, my_vp IN NUMBER
) IS
search_VP IFT_INFO_LAUF.VP%TYPE;
found_VP IFT_INFO_LAUF.VP%TYPE;
INFOversion number := 25;
BEGIN
BEGIN -- search SYFA_VP
etc
Make sure that
FPWL_VP_MAPPING.SYFA_VP
is the same type with
IFT_INFO_LAUF.VP
and make sure that
SELECT SYFA_VP INTO found_VP FROM FPWL_VP_MAPPING WHERE INFO_VP=search_VP ;
does not return multiple rows.
But I doubt that is the case with the error that you have given.
Since the error message refers to line 36 and the reference to found_VP in your code sample is on line 18, you've omitted the part of the code that actually has the problem.
It looks like you have a scope problem; you're declaring found_VP in an inner block (one level of DECLARE/BEGIN/END) and referring to it outside that block, either in the parent block or another one at the same level. The issue isn't where you're selecting into found_VP, it's (I think) that you're referring to it again later on, beyond the code you've posted, and therefore outside the block the variable is declared in.
To demonstrate, I'll declare l_name in an inner block, as you seem to have done:
create or replace procedure p42 is
begin
declare
l_name all_tables.table_name%TYPE;
begin
select table_name
into l_name -- this reference is OK
from all_tables
where table_name = 'EMPLOYEES';
end;
select table_name
into l_name -- this reference errors
from all_tables
where table_name = 'JOBS';
end;
/
Warning: Procedure created with compilation errors.
show errors
Errors for PROCEDURE P42:
LINE/COL ERROR
-------- -----------------------------------------------------------------
12/2 PL/SQL: SQL Statement ignored
13/7 PLS-00201: identifier 'L_NAME' must be declared
14/2 PL/SQL: ORA-00904: : invalid identifier
Notice that the error is reported against line 13, which is in the outer block; it doesn't complain about it in the inner block because it is in-scope there.
So, you need to declare the variable at the appropriate level. As Colin 't Hart says that is probably right at the top, between the IS and the first BEGIN, as that is the procedure-level DECLARE section (it doesn't need an explicit DECLARE keyword).

use of bind variable

Can we use a bind variable in oracle inside a procedure or function ?
I'm trying to update a bind variable inside my procedure. Can I do so in any case?
if (condition) then
:v_bind:=10;
end if;
Can I do the above thing inside a procedure or function..?
variable v_bind number;
create procedure abc as v_one
BEGIN
select count(a) into v_one from ab;
if(v_one<>0) then
:v_bind:=10;
end if;
Will I able to do this? It is showing me bad variable v_bind
You can't create a procedure with a bind variable in it because stored procedures are server-side objects and bind variables only exist on the client side.
Suppose I'm using SQL*Plus, and that I've created some bind variables. Once I exit SQL*Plus, any bind variables I created don't exist any more. However, stored procedures have to persist in the database, and hence they can't have any reference to anything that was created and then destroyed on the client.
Here's an example showing that you can't create a procedure that references a bind variable:
SQL> variable i number
SQL> exec :i := 0;
PL/SQL procedure successfully completed.
SQL> print :i
I
----------
0
SQL> create or replace procedure test_proc
2 as
3 begin
4 :i := 9;
5 end;
6 /
Warning: Procedure created with compilation errors.
SQL> show errors procedure test_proc;
Errors for PROCEDURE TEST_PROC:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/3 PLS-00049: bad bind variable 'I'
You can, however, pass a bind variable as an OUT parameter for a procedure. The procedure can then assign a value to the OUT parameter, and this value will then be stored in your bind variable.
Suppose we have the following procedure:
CREATE OR REPLACE PROCEDURE do_stuff (
p_output OUT INTEGER
)
AS
BEGIN
p_output := 6;
END;
We can use this to set a bind variable as follows:
SQL> variable i number
SQL> exec :i := 0;
PL/SQL procedure successfully completed.
SQL> print :i
I
----------
0
SQL> exec do_stuff(:i);
PL/SQL procedure successfully completed.
SQL> print :i
I
----------
6
No, you cannot do what you are asking. Bind variables in plsql are handled transparently. You do not explicitly code bind variables unless you are going to use 'execute immediate' to run the code outside of plsql like this:
declare
v_bind number := 1;
begin
execute immediate 'select * from table where x = :v_bind';
end;`
The following code uses bind variables as well, but it is handled transparently by plsql:
declare
v_bind number := 1
y number;
begin
select count(*) into y from table where x = v_bind;
end;
You can't bind a sqlplus variable in a session to a function/procedure. It will give you error of "Bad bind variable". You can actually just pass bind variable from your oracle session to any procedure.
Let's see a example
variable v1 NUMBER;
begin
select salary into :v1 from employees where employee_id = 100;
dbms_output.put_line(:v1);
end;
/
And if you run the above example by enclosing in procedure/function it will show you error.
create or replace procedure proc is
begin
select salary into :v1 from employees where employee_id = 100;
dbms_output.put_line(:v1);
end;
/
Error -
PROCEDURE proc compiled
Warning: execution completed with warning
3/20 PLS-00049: bad bind variable 'V1'
4/22 PLS-00049: bad bind variable 'V1'
Thus, it is not possible to use session-level bind variables in procedures/functions. In below example t2 is a bind variable
create or replace procedure proc is
t2 NUMBER;
begin
select salary into t2 from employees where employee_id = 100;
dbms_output.put_line(t2);
end;
/
You can call this procedure from sqlplus as
exec proc;

Resources