Error(14,7): PLS-00049: bad bind variable - oracle

I have tried everything but Oracle 11g Express Edition gives me this error for the procedure.
Error(14,7): PLS-00049: bad bind variable
Here is my procedure
create or replace procedure select_member_data
AS
memberdata MEMBER%rowtype;
member_ID MEMBER.MEMBER_ID%TYPE;
first_name MEMBER.FIRST_NAME%TYPE;
last_name MEMBER.LAST_NAME%TYPE;
address MEMBER.ADDRESS%TYPE;
total_rows number(2);
BEGIN
SELECT MEMBER_ID,first_name,last_name,address
INTO :memberdata
FROM MEMBER where member_id= 1 ;
IF sql%notfound THEN
dbms_output.put_line('no records fetched');
ELSIF sql%found THEN
dbms_output.put_line( total_rows ||' fetched');
END IF;
END;
here is my table
CREATE TABLE MEMBER (
MEMBER_ID INT PRIMARY KEY,
LAST_NAME VARCHAR2(25) NOT NULL,
FIRST_NAME varchar2(25),
ADDRESS varchar2(100),
CITY varchar2(30),
PHONE varchar2(15),
JOIN_DATE date DEFAULT SYSDATE NOT NULL
);

You are doing:
SELECT MEMBER_ID,first_name,last_name,address
INTO :memberdata
...
but memberdata is a local PL/SQL variable, not a bind variable, so it should just be:
SELECT MEMBER_ID,first_name,last_name,address
INTO memberdata
...
You also aren't fetching enough columns into your %rowtype variable. You table has seven columns, so your memberdata record variable has seven fields as well; but your query is only selecting four columns - which isn't enough. (Slightly confusingly, this is reported as too many values, rather than not enough values).
You can list all of the column names, but this is a rare occasion where it may be better (or at least justifiable) to use *:
SELECT *
INTO memberdata
...
Or as you have the other variables defined already you could do:
SELECT MEMBER_ID,first_name,last_name,address
INTO member_ID, first_name, last_name, address
...
although I'd stongly recommend you don't have variable names that are the same as column names; it's common to prefix local variable with something to identify them, e.g. l_member_id.
Your logic is flawed though. If your query doesn't get exactly one row then a no-data-found or too-many-rows exception will be thrown. (You can't have more than one because of the primary key here, but you could find none). The sql%notfound check won't be reached.

Related

SYS_REFCURSOR is returning all the rows from table without considering the IN parameter

I am facing a weird problem here.
PROCEDURE USL_EMPLOYEEBYID (
EMPLOYEE_ID IN NUMBER,
EMPIDCURSOR OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN EMPIDCURSOR FOR
SELECT emp.employee_id,emp.employee_name,emp.present_address,emp.permanent_address,emp.status
FROM Employee_Info emp
WHERE emp.employee_id = EMPLOYEE_ID;
END;
This procedure should give me a single employee upon entering the employee Id. But it is returning all the employees.
What am I doing wrong here?
In your query, Oracle interprets EMPLOYEE_ID as the column EMPLOYEE_ID, not the input parameter, here you find something more; in this way, your where condition is something like a=a.
Change the parameter name to distinguish it from the table column:
PROCEDURE USL_EMPLOYEEBYID (
p_EMPLOYEE_ID IN NUMBER,
po_EMPIDCURSOR OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN po_EMPIDCURSOR FOR
SELECT emp.employee_id,emp.employee_name,emp.present_address,emp.permanent_address,emp.status
FROM Employee_Info emp
WHERE emp.employee_id = p_EMPLOYEE_ID;
END;
this is a good practice, to always know in your code whether you are handling an input parameter, a local variable, a column and so on

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.

PLS-00103: Encountered Symbol DECLARE/EOF when trying to increment values with a sequence

I'm working on a procedure that will declare a variable, take the value from a procedure that increments, and inserts that value along with other parameters into a table. I thought I had it all worked out, but then I got hit with PLS-00103: Encountered symbol "DECLARE" and Encountered symbol "end-of-file". I feel like I'm so close, so any help would be majorly appreciated! Thank you!
create or replace procedure Order_Create(date_order string, cust_id char, total float, employ_id number)
is
DECLARE NewKey;
BEGIN
NewKey := order_auto_inc.nextval;
UPDATE Progressive_Keys set Order_Limit = NewKey;
insert into ORDERS VALUES (Progressive_Keys.Order_Limit, to_date(date_order, 'yyyy-mm-dd'), cust_id, total, employ_id);
commit;
END;
Remove the declare it's not needed in a stored procedures (as documented in the manual).
A variable declaration needs a data type.
As the parameter order_date is supposed to be a date, it should be declared with that type.
You can't access the column order_limit outside of a statement that uses the table progressive_keys so you need to use the variable in the insert statement as well.
It's also good coding practice to always list the target columns in an INSERT statement (note that I just invented some column names for the orders table you will have to adjust them to reflect the real names in your table)
create or replace procedure Order_Create(date_order date, cust_id varchar, total float, employ_id number)
is
NewKey number;
BEGIN
NewKey := order_auto_inc.nextval;
UPDATE Progressive_Keys set Order_Limit = NewKey;
insert into ORDERS (some_key, order_date, customer_id, total, employee_id)
VALUES (newkey, date_order, cust_id, total, employ_id);
commit;
END;
The UPDATE looks a bit strange as it will update all rows in the thable progressive_keys not just one row.

How to validate or get the value from the Input parameter of (Type Table) in Stored procedure in Oracle PL SQL?

I need to check the value in the Input parameter whether it is NULL or NOT in Stored procedure. The Input Parameter is of Table type and contains nested object in it. It contains 3 attributes - employee id, manager_id and address. I need to check if the manager_id and employee_id is NULL or not.Based on the values if it is NULL, i need to insert into two different tables.
CREATE OR REPLACE PACKAGE BODY order_mgr
IS
PROCEDURE ins_trees ( p_emp_details_in IN trees_type_t,
p_nrmployee_Id IN NUMBER
)
BEGIN
-- Condition goes here.. please let me know how to check this in the table type object as it contains nested object.
-- IF the manager_id is NULL in the trees_type_t type object
THEN
INSERT into emp (employee_id, address)
values(p_emp_details_in.employee_id, p_emp_details_in.address_id);
END IF;
-- Condition goes here.. please let me know how to check this in the table type object as it contains nested object.
-- IF the (employee_id is NULL in the trees_type_t type object then
INSERT into manager (manager_id, address)
values(p_emp_details_in.manager_id,p_emp_details_in.address_id);
END IF;
END;
END;
/
Object type:
create or replace TYPE trees_type_t AS TABLE OF tree_obj_type;
create or replace TYPE tree_obj_type AS OBJECT
(
employee_id VARCHAR2(10),
manager_id VARCHAR2(10),
address VARCHAR2(100),
);
Please suggest and help me.
First, I assume that since you're accepting a collection, your intention is to iterate over each element in the collection. Your code doesn't have a loop which I assume you intended to have. Second, I assume that the collection is dense (i.e. there are no indexes that are unpopulated)
You likely want something like
FOR i IN 1 .. p_emp_details_in.count
LOOP
IF p_emp_details_in(i).employee_id IS NOT NULL
THEN
INSERT into emp (employee_id, address)
values(p_emp_details_in(i).employee_id, p_emp_details_in(i).address_id);
END IF;
IF p_emp_details_in(i).manager_id IS NOT NULL
THEN
INSERT into manager (manager_id, address)
values(p_emp_details_in(i).manager_id,p_emp_details_in(i).address_id);
END IF;
END LOOP;
Of course, if you don't need to use PL/SQL, you could do this with a single INSERT ALL
INSERT ALL
WHEN employee_id IS NOT NULL
INTO emp(employee_id, address) VALUES( employee_id, address )
WHEN manager_id IS NOT NULL
INTO manager( manager_id, address ) VALUES( manager_id, address )
SELECT employee_id, manager_id, address
FROM TABLE( p_emp_details_in );

How to programmatically set table name in PL/SQL?

I created the following simple PL/SQL stored procedure example to ask a specific question. This procedure inserts an employee name and id number into a table called employees_???. The ??? is explained below.
PROCEDURE hire_employee (emp_id IN INTEGER, name IN VARCHAR2, country IN VARCHAR2)
AS
BEGIN
INSERT INTO employees_??? VALUES (emp_id, name, 1000);
END hire_employee;
What I need is to set the table name based on the IN variable country. For example,
If country = 'usa', I want the INSERT line to read:
INSERT INTO employees_usa VALUES (emp_id, name, 1000);
If country = 'germany', I want the INSERT line to read:
INSERT INTO employees_germany VALUES (emp_id, name, 1000);
If country = 'france', I want the INSERT line to read:
INSERT INTO employees_france VALUES (emp_id, name, 1000);
etc...
Is there a way to do this in PL/SQL by substituting something in place of employee_??? so only one line of code for INSERT is used? Or is using a case or if/then/else statement the best way?
To answer your question, you have to use execute immediate and create your statement dynamically.
create or replace procedure hire_employee (
emp_id IN INTEGER
, name IN VARCHAR2
, country IN VARCHAR2 ) is
-- maximum length of an object name in Oracle is 30
l_table_name varchar2(30) := 'employees_' || country;
begin
execute immediate 'insert into ' || l_table_name
|| ' values (:1, :2, 1000)'
using emp_id, name;
end hire_employee;
However, this is a massively over-complicated way of storing the data. If you want to select all data you have to union large numbers of tables.
It would be far better to normalise the database properly and add country to an employees table.
Something like the following:
create table employees (
emp_id number(16)
, country varchar2(3) -- ISO codes
, name varchar2(4000) -- maximum who knows what name people might have
, < other_columns >
, constraint pk_employees primary key ( emp_id )
);
Your procedure then becomes a very simple insert statement:
create or replace procedure hire_employee (
emp_id in integer
, name in varchar2
, country in varchar2 ) is
insert into employees
values ( emp_id, country, name, 1000 );
end hire_employee;
You can use dynamic SQL and the EXECUTE IMMEDIATE construct. In this, you construct the query as a string and then execute it. A good example is at http://docs.oracle.com/cd/B10500_01/appdev.920/a96590/adg09dyn.htm

Resources