Getting invalid identifier ORA-00904 - sql

I have a procedure
Create or replace procedure schoolstudents(
LS1 OUT NUMBER,
LS2 OUT NUMBER,
val in VARCHAR2)
IS
val1 VARCHAR2(128);
schoolId NUMBER;
BEGIN
val11 := val;
schoolId := function(val1);
insert := 'Insert into sname values("a","b") RETURNING '||schoolId||' into :0, '||schoolId||' into :1';
Execute immediate insert USING OUT LS1,OUT LS2;
COMMIT;
I am getting an error
ORA-00933 : SQL command not properly ended.

You need an END; statement to complete the PL/SQL block.
You have not declared the insert variable and insert is a keyword and you should not use it as a variable name.
String literals need to be enclosed in single quotes (rather than double quotes).
The syntax for RETURNING INTO is RETURNING column1, column2 INTO :1, :2.
If you have the setup:
CREATE TABLE sname (
col1 VARCHAR2(20),
col2 VARCHAR2(20)
);
CREATE FUNCTION function( tablename IN VARCHAR2) RETURN NUMBER
IS
BEGIN
RETURN 1;
END;
/
Then your procedure would be:
Create or replace procedure schoolstudents(
LS1 OUT NUMBER,
LS2 OUT NUMBER,
tablename in VARCHAR2)
IS
lname VARCHAR2(128);
schoolId NUMBER;
insert_sql VARCHAR2(200);
BEGIN
lname := tablename;
schoolId := function(lname);
insert_sql := 'Insert into sname values(''a'',''b'') RETURNING '||schoolId||', '||schoolId||' into :1, :2';
EXECUTE IMMEDIATE insert_sql RETURNING INTO LS1, LS2;
COMMIT;
END;
/
However, you can rewrite your procedure without the dynamic SQl as:
Create or replace procedure schoolstudents(
LS1 OUT NUMBER,
LS2 OUT NUMBER,
tablename in VARCHAR2)
IS
schoolId NUMBER;
BEGIN
schoolId := function(tablename);
Insert into sname values('a','b');
LS1 := schoolId;
LS2 := schoolId;
COMMIT;
END;
/
db<>fiddle here

Quite a few errors. When fixed, it compiles (can't tell will it do what you planned).
you used insert variable, but never declared it. Anyway, you have to change its name, insert is for inserting
function(lname) is what, exactly? You can't name a function function (similarly to insert I mentioned previously). I have no idea what it is so I commented it out
don't use double, but single quotes for strings. However, in dynamic SQL, you have to escape them (by doubling them), or - simpler - use the q-quoting mechanism
Finally:
SQL> CREATE OR replace PROCEDURE schoolstudents(
2 ls1 OUT NUMBER,
3 ls2 OUT NUMBER,
4 tablename IN VARCHAR2
5 )IS
6 lname VARCHAR2(128);
7 schoolid NUMBER;
8 l_insert varchar2(200); --> not INSERT, it is reserved
9 BEGIN
10 lname := tablename;
11 schoolId := lname; --function(lname); --> what is FUNCTION?
12 l_insert := q'[Insert into sname values('a','b') --> q-mecanism; single, not double quotes
13 RETURNING ]'||schoolId||' into :0, '||schoolId||' into :1';
14 Execute immediate l_insert
15 USING OUT ls1, OUT ls2;
16 COMMIT;
17 END;
18 /
Procedure created.
SQL>

As others have pointed out there are quite a few problems with this code. What no one pointed out is that there doesn't appear to be any reason to use an EXECUTE IMMEDIATE here. I suggest:
Create or replace procedure schoolstudents(LS1 OUT NUMBER,
LS2 OUT NUMBER,
tablename in VARCHAR2)
IS
schoolId NUMBER;
BEGIN
schoolId := some_function(tablename);
Insert into sname values('a', 'b');
COMMIT;
LS1 := schoolId;
LS2 := schoolID;
END schoolstudents;

Related

How to write a PL/SQL procedure with an Instead Of Trigger as Dynamic SQL?

I wrote a PL/SQL function and am using dynamic SQL to execute a Create trigger statement as follows :-
CREATE OR REPLACE FUNCTION register_driver1(driver_name IN VARCHAR, pass_word IN VARCHAR) RETURN NUMBER AS
sql_stmt VARCHAR2(500);
driver_id NUMBER;
new_view_name VARCHAR(50); --<-----Line 4
BEGIN
--function statements
sql_stmt := 'CREATE OR REPLACE TRIGGER reg_vehicle
INSTEAD OF INSERT ON '||new_view_name||
' FOR EACH ROW
DECLARE
vehicle_id NUMBER;
BEGIN
vehicle_id := vehicle_ids.nextval
INSERT INTO Vehicles VALUES(:NEW.Model, :NEW.Seats, :NEW.reg_no, vehicle_id, '||driver_id||');
END;';
EXECUTE IMMEDIATE sql_stmt; --<-----Line 32
--Remaining function body
END;
/
Here, the variables new_view_name, driver_id are defined above this code snippet. Vehicle is a table(Model, Seats, Reg_no, vehicel_id, driver_id) and reg_vehicle(Model, Seats, Reg_no) is a view having Vehicles of a particular driver_id.
vehicle_ids is a sequence created outside the procedure.
The above shows compilation error at the EXECUTE IMMEDIATE line. What is the correct way to do this?
The error shown when function is called with some driver_name and pass_word:-
ORA-24344: success with compilation error ORA-06512: at "ADMIN.REGISTER_DRIVER1", line 32 ORA-06512: at line 4
Well, I wouldn't recommend creating objects dynamically.
If you - for some reason - insist on that, then another problem: you can't perform DDL here as you'd call a function as e.g.
select register_driver1(...) from dual;
and get
ORA-14552: cannot perform a DDL, commit or rollback inside a query or DML
So - switch to a procedure with an OUT parameter to return whatever that function is supposed to return.
As of error you got: you miss BEGIN. Something like this compiles:
SQL> CREATE OR REPLACE PROCEDURE register_driver1 (driver_name IN VARCHAR,
2 pass_word IN VARCHAR)
3 AS
4 sql_stmt VARCHAR2 (500);
5 driver_id NUMBER;
6 new_view_name VARCHAR (50);
7 BEGIN
8 sql_stmt :=
9 'CREATE OR REPLACE TRIGGER reg_vehicle
10 INSTEAD OF INSERT ON '
11 || new_view_name
12 || ' FOR EACH ROW
13 DECLARE
14 vehicle_id NUMBER;
15 BEGIN
16 vehicle_id := vehicle_ids.nextval
17 INSERT INTO Vehicles VALUES(:NEW.Model, :NEW.Seats, :NEW.reg_no, vehicle_id, '
18 || driver_id
19 || ');
20 END;';
21
22 -- EXECUTE IMMEDIATE sql_stmt;
23 DBMS_OUTPUT.put_line (sql_stmt);
24 END;
25 /
Procedure created.
SQL>
SQL> SET SERVEROUTPUT ON;
SQL> EXEC register_driver1('a', 'b');
CREATE OR REPLACE TRIGGER reg_vehicle
INSTEAD OF INSERT ON FOR
EACH ROW
DECLARE
vehicle_id NUMBER;
BEGIN
vehicle_id := vehicle_ids.nextval
INSERT
INTO Vehicles VALUES(:NEW.Model, :NEW.Seats, :NEW.reg_no, vehicle_id, );
END;
PL/SQL procedure successfully completed.
SQL>

How to execute stored function in Oracle PL/SQL

I want to execute this stored function, and insert data in table t
I tried to find solution, but unsuccessfully
CREATE TABLE t (id number
, name varchar2(32)
, time date);
CREATE OR REPLACE PACKAGE t_api AS
FUNCTION func_ins (
p_row IN t%rowtype
) RETURN t.id%TYPE;
END t_api;
/
CREATE OR REPLACE PACKAGE BODY t_api AS
FUNCTION func_ins (
p_row IN t%rowtype
) RETURN t.id%TYPE
IS
l_id t.id%TYPE;
BEGIN
INSERT INTO t VALUES p_row RETURNING id INTO l_id;
RETURN l_id;
END func_ins;
END t_api;
/
declare
p_row t%rowtype;
begin
p_row.id := 1;
p_row.name := 'name';
p_row.time := sysdate;
t_api.func_ins(p_row);
end;
/
I got
PLS-00221
Thanks in advance
It works perfectly ,however i wouldn't recommend this design as its not a good practice to perform a DML within a function. Rather create a procedure instead of function and retrieve the Id using the out parameter.
Anonymous block to test the function when table is empty.You assign values for %ROWTYPE variable and insert.
declare
t_row t%rowtype;
x t.id%type;
begin
t_row.id := 2;
t_row.name := 'Test2';
t_row.time := sysdate;
x := t_api.func_ins(t_row);
dbms_output.put_line('x '||x);
end;
Output is
x 2
Modified code with Procedure to achieve the same result is below,
CREATE OR REPLACE PACKAGE t_api AS
FUNCTION func_ins (
p_row IN t%rowtype
) RETURN t.id%TYPE;
PROCEDURE proc_ins (
p_row IN t%rowtype,
l_id out t.id%TYPE
);
END t_api;
/
CREATE OR REPLACE PACKAGE BODY t_api AS
FUNCTION func_ins (
p_row IN t%rowtype
) RETURN t.id%TYPE
IS
l_id t.id%TYPE;
BEGIN
INSERT INTO t VALUES p_row RETURNING id INTO l_id;
RETURN l_id;
END func_ins;
PROCEDURE proc_ins (
p_row IN t%rowtype,
l_id out t.id%TYPE
)
IS
BEGIN
INSERT INTO t VALUES p_row RETURNING id INTO l_id;
END proc_ins;
END t_api;
/
Anonymous block to test the procedure,
declare
t_row t%rowtype;
x t.id%type;
begin
t_row.id := 3;
t_row.name := 'Test3';
t_row.time := sysdate;
t_api.proc_ins(t_row,x);
dbms_output.put_line('x '||x);
end;
Output is
x 3

I want to create a table and insert a row in same table during run time using dynamic sql

I have created a procedure that accepts table name, 2 column names and 2 values that needed to be inserted on create table.
create or replace procedure SP_TABLE(P_TAB IN VARCHAR2,P_COL_1 IN VARCHAR2,P_COL_2 VARCHAR2,P_ID IN NUMBER,P_NAME IN VARCHAR2)
AS
v_sql varchar2(2000);
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE '||P_TAB||' ('||P_COL_1||' NUMBER, '||P_COL_2 ||' VARCHAR2(20))';
v_sql := 'insert into ' ||P_TAB||'values (:1,:2)';
EXECUTE IMMEDIATE v_sql USING P_ID,P_NAME;
END;
/
The procedure was successfully created without any errors. However when i ran the below script i got error like 'ORA-00928: missing SELECT keyword
ORA-06512: at "SQL_PXADYXDREZPVPJSALLEGOZJOB.SP_TABLE", line 7'.
DECLARE
V_TAB VARCHAR2(20) := 'TABLE1';
V_COL1 VARCHAR2(20) := 'ID';
V_COL2 VARCHAR2(20) := 'NAME';
V_ID NUMBER := 1;
V_NAME VARCHAR2(20):= 'RAJA';
BEGIN
SP_TABLE(V_TAB,V_COL1,V_COL2,V_ID,V_NAME);
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_STACK);
END;
/
some one help me with this.
You can add space before values
create or replace procedure SP_TABLE(P_TAB IN VARCHAR2,P_COL_1 IN VARCHAR2,P_COL_2 VARCHAR2,P_ID IN NUMBER,P_NAME IN VARCHAR2)
AS
v_sql varchar2(2000);
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE '||P_TAB||' ('||P_COL_1||' NUMBER, '||P_COL_2 ||' VARCHAR2(20))';
v_sql := 'insert into ' ||P_TAB||' values (:1,:2)';
EXECUTE IMMEDIATE v_sql USING P_ID,P_NAME;
END;
/

How to pass values in anonymous block with plsql table parameter

Table abc has the following column
approved_ain
1
2
12
34
i have a procedure
create or replace procedure abc( p_admin varchar2,
p_approved_ain abc.approved_ain)--plsql table in parameter
begin
end;
now when i call this procedure in an anonymous block :-
declare
l_Admin varchar2(100);
l_approved_ain abc.approved_ain;
begin
abc(l_Admin ,l_approved_ain);
commit;
end;
How can i pass values of the approved_ain of plsql table to this anonymous block.? that is i want to test it by passing the values of abc table approved_ain column.......
Answer :
declare
l_Admin varchar2(100);
l_approved_ain abc.approved_ain;
begin
l_approved_ain(1) :=123;
l_approved_ain(2) :=4645;
abc(l_Admin ,l_approved_ain);
commit;
end;
Given the fact that you only want to test, what about just setting the values in the anonymous block:
declare
l_Admin varchar2(100) := 'string';
l_approved_ain abc.approved_ain := ???;
begin
abc(l_Admin ,l_approved_ain);
commit;
end;

Error in stored procedure execution in oracle

create procedure proc_insert_salary(salary_emp in NUMBER,
empid in NUMBER(10),
desig in varchar2(20))
begin
DECLARE
gr_sal,hr,da,pf number;
BEGIN
set hr:= salary_emp*(15/100);
set da:= salary_emp*(8/100);
set pf := salary_emp*(35/100);
set gr_sal := salary_emp+hr+da-pf;
insert into emp_salary_details values (empid,desig, salary_emp, gr_sal);
end;
call proc_insert_salary (45000,10100,'C.E.O.')
when I call this procedure it gives error its in invalid state.
While #Guneli's answer is adequate, there's really no reason for the second block in this case. The following would be equivalent (and slightly simpler).
CREATE OR REPLACE PROCEDURE proc_insert_salary (salary_emp IN NUMBER,
empid IN NUMBER,
desig IN VARCHAR2) AS
hr NUMBER := salary_emp * (15 / 100);
da NUMBER := salary_emp * (8 / 100);
pf NUMBER := salary_emp * (35 / 100);
gr_sal NUMBER := salary_emp + hr + da - pf;
BEGIN
INSERT INTO emp_salary_details
VALUES (empid,
desig,
salary_emp,
gr_sal);
END;
/
Also, you should not that if you're going to have any other SQL in the same script (such as the call) then you need to end the procedure definition with a slash (/). This tells Oracle that procedure is finished and that it should compile it. Really, it's a good practice to always include it after procedural code.
Well, try this instead:
CREATE OR REPLACE PROCEDURE proc_insert_salary(
salary_emp IN NUMBER,
empid IN NUMBER,
desig IN VARCHAR2)
AS
BEGIN
DECLARE
gr_sal NUMBER;
hr NUMBER;
da NUMBER;
pf NUMBER;
BEGIN
hr := salary_emp*(15/100);
da := salary_emp*(8/100);
pf := salary_emp*(35/100);
gr_sal := salary_emp+hr+da-pf;
INSERT INTO emp_salary_details VALUES (empid,desig, salary_emp, gr_sal);
END;
END;
The things to note are that:
1) You can not show the size for the parameters of subprograms in PL/SQL, so NUMBER(10) or VARCHAR2(20) are incorrect.
2)The one line declaration of variables is not supported in PL/SQL, so instead of gr_sal,hr,da,pf number; you should use
gr_sal NUMBER;
hr NUMBER;
da NUMBER;
pf NUMBER;
3)To assign a value to variable you should not use SET, the ':=' is enough.
4)Also you have missed the 'end' clause for your second 'begin'.