Im a learning plsql and im trying to create procedure and calling procedure inside another procedure and i can get desired output. But when i tried to create procedure inside another procedure instead of calling another procedure, im getting the below error
"23/1 PLS-00103: Encountered the symbol "PROCEDURE" when expecting one of the following: ( begin case declare end exception exit for goto if loop mod null pragma raise return select update while with << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge The symbol "declare" was substituted for "PROCEDURE" to continue.
23/18 PLS-00103: Encountered the symbol "." when expecting one of the following: in out ... long double ref char time timestamp interval date binary national character nchar
Errors: check compiler log
"
CREATE OR REPLACE PROCEDURE pro (
empn NUMBER,
emp OUT emp5%rowtype
) IS
salar number;
BEGIN
SELECT
a.*
INTO emp
FROM
emp5 a
WHERE
a.empno = empn;
dbms_output.put_line('The hire date is'
|| ' '
|| emp.hiredate);
dbms_output.put_line('Name is'
|| ' '
|| emp.ename);
procedure p44(emp.hiredate in date,emp.ename varchar,sal out number) IS
salar NUMBER;
BEGIN
SELECT
e.sal
INTO salar
FROM
emp5 e
WHERE
e.hiredate = hire
AND e.ename = enamee;
dbms_output.put_line('salary of the employee'
|| ' '
|| enamee
|| 'is '
|| salar);
END p43;
/
If i give empno number as input to procedure pro, i need output with employees hiredate,employee's name and employee's salary like the below one
The hire date is 20-FEB-81
Name is ALLEN
salary of the employee ALLEN is 1600
A procedure is a single program unit with the structure of:
create or replace procedure p43 () is
...
begin
…
end;
/
Your code has two instances of PROCEDURE and that's what the compiler is complaining about.
If you want two separate procedures you need two separate CREATE statements:
create or replace procedure p43 () is
...
begin
…
end p43;
/
create or replace procedure p44 () is
...
begin
…
end p44;
/
But if what you want is P44 as a private procedure only accessible within the context of P43 you can do that, by defining the procedure in the declaration section after any variable declarations:
create or replace procedure p43 () is
…
procedure p44 () is
...
begin
…
end p44;
begin
…
p44(…);
end p43;
/
Also this is not how we declare parameters.
procedure p44(emp.hiredate in date,emp.ename varchar,sal out number) IS
Give them unique names, say by prefixing them with p_, and if you like use the table column datatype. Something like this:
procedure p44(p_hiredate in emp.hiredate%type
,p_ename in emp.ename%type
,p_sal out emp.sal%type) IS
Giving parameters a distinct name prevents scope confusion when using parameters in SQL statements:
You can not create procedure within procedure.
Procedure is a single object and must be created alone. You can call one procedure from another.
You can use package to create multiple procedures inside single package but in that case also, procedure must be created standalone.
-- procedure must be created standalone
Create or replace procedure p44
As
Begin
-- code
End p44;
/
Create or replace procedure pro
As
Begin
P44; -- call to existing procedure
-- code
End pro;
/
So your case will go like this:
procedure p44(hiredate in date,ename varchar,sal out number) IS
salar NUMBER;
BEGIN
SELECT
e.sal
INTO salar
FROM
emp5 e
WHERE
e.hiredate = hire
AND e.ename = ename;
dbms_output.put_line('salary of the employee'
|| ' '
|| ename
|| 'is '
|| salar);
END p44;
/
CREATE OR REPLACE PROCEDURE pro (
empn NUMBER,
emp OUT emp5%rowtype
) IS
salar number;
BEGIN
SELECT
a.*
INTO emp
FROM
emp5 a
WHERE
a.empno = empn;
dbms_output.put_line('The hire date is'
|| ' '
|| emp.hiredate);
dbms_output.put_line('Name is'
|| ' '
|| emp.ename);
P44(emp.hiredate, emp.ename, salr):
END pro;
/
Cheers!!
Related
The procedure uses the previous function to display the list of the products: num, designation and mention on the application.
SET SERVEROUTPUT ON;
CREATE OR REPLACE FUNCTION STORE(num_produit IN INTEGER) RETURN VARCHAR AS
N INTEGER := 0;
incre INTEGER := 0;
BEGIN
SELECT SUM(qte) INTO N FROM Ligne_Fact WHERE num_produit = produit;
IF N > 15 THEN
RETURN 'fort';
ELSIF N > 11 THEN
RETURN 'moyen';
END IF;
RETURN 'faible';
END;
/
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
SELECT num, designation, STORE(num) INTO SOME_VAR FROM Produit;
dbms_output.enable();
dbms_output.put_line('result : '|| SOME_VAR);
END;
/
BEGIN
SHOW_PRODUITS;
END;
/
I am sure that all the tables are filled with some dummy data, but I am getting the following error:
Function STOCKER compiled
Procedure AFFICHER_PRODUITS compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
4/4 PL/SQL: SQL Statement ignored
4/56 PL/SQL: ORA-00947: not enough values
Errors: check compiler log
Error starting at line : 28 in command -
BEGIN
AFFICHER_PRODUITS;
END;
Error report -
ORA-06550: line 2, column 5:
PLS-00905: object SYSTEM.SHOW_PRODUITS is invalid
ORA-06550: line 2, column 5:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
The first major mistake you've made is to create your objects in SYSTEM schema. It, just like SYS, are special and should be used only for system maintenance. Create your own user and do whatever you're doing there.
As of your question: select returns 3 values, but you're trying to put them into a single some_var variable. That won't work. Either add another local variables (for num and designation), or remove these columns from the select:
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
SELECT STORE(num) INTO SOME_VAR FROM Produit; --> here
dbms_output.enable();
dbms_output.put_line('result : '|| SOME_VAR);
END;
/
Code, as you put it, presumes that produit contains a single record (it can't be empty nor it can have 2 or more rows because you'll get various errors).
Maybe you wanted to access all rows; in that case, consider using a loop, e.g.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
FOR cur_r IN (SELECT num, designation, STORE(num) some_var FROM Produit) LOOP
dbms_output.put_line(cur_r.num ||', '|| cur_r.designation ||', result : '|| cur_r.some_var);
END LOOP;
END;
/
Then
set serveroutput on
BEGIN
SHOW_PRODUITS;
END;
/
You are trying to compile some stored routine which calls another stored routine named AFFICHER_PRODUITS and that routine calls SHOW_PRODUITS but SHOW_PRODUITS does not compile, hence the error. (By the way, it is recommended not to create your own stored routines in the SYSTEM schema.)
SHOW_PRODUITS does not compile because of this line:
SELECT num, designation, STORE(num) INTO SOME_VAR FROM Produit;
It appears that you want to get the query results as a string. In order to do that, you need to concatenate the column values, i.e.
SELECT num || designation || STORE(num) INTO SOME_VAR FROM Produit;
Of-course if all you want to do is display the query results, using DBMS_OUTPUT, you can declare a separate variable for each column.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_NUM Produit.num%type;
SOME_DES Produit.designation%type;
SOME_VAR VARCHAR2(6);
BEGIN
SELECT num
,designation
,STORE(num)
INTO SOME_NUM
,SOME_DES
,SOME_VAR
FROM Produit;
dbms_output.enable();
dbms_output.put_line('result : ' || SOME_NUM || SOME_DES || SOME_VAR);
END;
Note that if the query returns more than one row, you will [probably] need to use a cursor.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_NUM Produit.num%type;
SOME_DES Produit.designation%type;
SOME_VAR VARCHAR2(6);
--
CURSOR c1 IS
SELECT num, designation, STORE(num) FROM Produit;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO SOME_NUM, SOME_DES, SOME_VAR;
EXIT WHEN c1%NOTFOUND;
dbms_output.put_line('result : ' || SOME_NUM || SOME_DES || SOME_VAR);
END LOOP;
CLOSE c1;
END;
I am writing this below stored procedure but i am also getting the exception while compiling the procedure in oracle, below is the procedure
CREATE OR REPLACE PACKAGE BODY TEST_TABLE AS
PROCEDURE TEST_TABLE
--This procedure will delete partitions for the following tables:
--TEST_TABLE
BEGIN
FOR cc IN
(
SELECT partition_name, high_value
FROM user_tab_partitions
WHERE table_name = 'TEST_TABLE'
)
LOOP
EXECUTE IMMEDIATE 'BEGIN
IF sysdate >= ADD_MONTHS(' || cc.high_value || ', 3) THEN
EXECUTE IMMEDIATE
''ALTER TABLE TEST_TABLE DROP PARTITION ' || cc.partition_name || '
'';
END IF;
dbms_output.put_line('drop partition completed');
END;';
END LOOP;
exception
when others then
dbms_output.put_line(SQLERRM);
END;
END;
/
and the exception that I am getting it while compiling is Please advise how to overcome from this.
Error(7,1): PLS-00103: Encountered the symbol "BEGIN" when expecting one of the following: ( ; is with authid as cluster order using external deterministic parallel_enable pipelined result_cache The symbol ";" was substituted for "BEGIN" to continue.
Error(22,25): PLS-00103: Encountered the symbol "DROP" when expecting one of the following: * & = - + ; < / > at in is mod remainder not rem return returning <an exponent (**)> <> or != or ~= >= <= <> and or like like2 like4 likec between into using || bulk member submultiset
You need to make correct quotation as below( and one more is keyword just after PROCEDURE TEST_TABLE "thanks to Alex who make me awaken" ) :
CREATE OR REPLACE PACKAGE BODY PKG_TEST_TABLE IS
PROCEDURE TEST_TABLE IS
--This procedure will delete partitions for the following tables:
--TEST_TABLE
BEGIN
FOR cc IN
(
SELECT partition_name, high_value
FROM user_tab_partitions
WHERE table_name = 'TEST_TABLE'
)
LOOP
BEGIN
IF sysdate >= ADD_MONTHS(cc.high_value, 3) THEN
EXECUTE IMMEDIATE
'ALTER TABLE TEST_TABLE DROP PARTITION ' || cc.partition_name;
Dbms_Output.Put_Line('Dropping partition is completed.');
END IF;
END;
END LOOP;
EXCEPTION WHEN Others THEN Dbms_Output.Put_Line( SQLERRM );
END TEST_TABLE;
END PKG_TEST_TABLE;
/
As a little suggestion use a different name for package than procedure such as PKG_TEST_TABLE against confusion.
Edit : of course you need to create a specification part for a package before the body part of the package :
CREATE OR REPLACE PACKAGE PKG_TEST_TABLE IS
PROCEDURE TEST_TABLE;
END PKG_TEST_TABLE;
/
The first error message tells you something is missing before BEGIN, and even mentions the two possible options in the 'when expecting' list. You need to change it to:
PROCEDURE TEST_TABLE IS
-- ^^
Or you can use AS instead of IS if you prefer...
The second error is because you have a string literal embedded in your dynamic SQL and you haven't escaped the single quotes, though you have elsewhere:
...
dbms_output.put_line(''drop partition completed'');
-- ^ ^
END;';
You could use the alternative quoting mechanism instead.
I'm not sure why you're doing two levels of dynamic SQL; you can do the dbms_output() and evaluate cc.high_value statically, and decide whether to make the alter call, with only that part dynamic (as #BarbarosÖzhan has shown, so I wont repeat that!). Or do the high-value check within the cursor query.
I am still getting exception Error(1,14): PLS-00304: cannot compile body of 'TEST_TABLE' without its specification
If you want a package then you have to create its specification before you try to create its body:
CREATE OR REPLACE PACKAGE TEST_TABLE AS
PROCEDURE TEST_TABLE;
END TEST_TABLE;
/
CREATE OR REPLACE PACKAGE BODY TEST_TABLE AS
PROCEDURE TEST_TABLE IS
BEGIN
FOR cc IN
...
LOOP
...
END LOOP;
END TEST_TABLE; -- end of procedure
END TEST_TABLE; -- end of package
/
Having the package name the same as a procedure within it is a bit odd and confusing.
But maybe you didn't actually want a package at all, and were trying to create a standalone procedure, in which case just remove the package-body part:
CREATE OR REPLACE PROCEDURE TEST_TABLE AS
BEGIN
FOR cc IN
...
LOOP
...
END LOOP;
END TEST_TABLE; -- end of procedure
/
Read more.
I would strongly suggest you get rid of the exception handler, and I've left that out of those outlines - you should let any exception flow back to the caller. You don't know that whoever calls this will even have output enabled, so might well not even see the message you're printing instead. Only ever catch exceptions you can handle and need to handle at that point.
I am a newbie in plsql and trying to implement a code that uses procedure to perform some task.I am using oracle 10g.I have already made a package named stu_pack and am trying to make package body but in vain.Please help.
I want to make a procedure that gives student details for given course name.
the code is as below.
the error message is:
ERROR at line 14: PLS-00103: Encountered the symbol "PROCEDURE" when
expecting one of the following: ; delete exists prior
The symbol ";" was substituted for "PROCEDURE" to continue.
create or replace package body stu_pack as
procedure proc1(cname IN number) as
l_cname number(2);
CREATE OR REPLACE PACKAGE BODY stu_pack AS
PROCEDURE proc1 (
cname IN NUMBER
) AS
l_cname NUMBER(2);
cur1 student%rowtype;
CURSOR c1 IS SELECT
s.*
FROM
student s,
course c,
learn l
WHERE
c.cname = l_cname
AND c.cid = l.cid
AND s.sid = l.sid;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO cur1;
EXIT WHEN c%notfound;
dbms_output.put_line('student roll number:'
|| cur1.sid
|| ' student
name:'
|| cur1.sname
|| ' phone number:'
|| cur1.phone);
END LOOP;
CLOSE c1;
END procedure proc1;
END stu_pack;
/
You need to change the line end procedure proc1;
It should be simply
end;
oR
end proc1;
How can i rewrite below pl/sql block in order to avoid hard code column names one by one ? Below data are from OE schema. For orders table there are 8 columns on this table. Is it possible to output the results without hard code column names ? Any help is appreciated.
create or replace PACKAGE show_details AS
TYPE rt_order IS REF CURSOR RETURN orders%ROWTYPE;
TYPE typ_cust_rec IS RECORD
(cust_id NUMBER(6), cust_name VARCHAR2(20),
custphone customers.phone_numbers%TYPE,
credit NUMBER(9,2), cust_email VARCHAR2(30));
TYPE rt_cust IS REF CURSOR RETURN typ_cust_rec;
--Get order detail
PROCEDURE get_order(p_orderid IN NUMBER, p_cv_order IN OUT rt_order);
--Get customer detail
PROCEDURE get_cust(p_custid IN NUMBER, p_cv_cust IN OUT rt_cust);
END show_details;
create or replace PACKAGE BODY show_details
AS
PROCEDURE get_order (p_orderid IN NUMBER, p_cv_order IN OUT rt_order)
IS
BEGIN
OPEN p_cv_order FOR
SELECT * FROM orders
WHERE order_id = p_orderid;
-- CLOSE p_cv_order
END get_order;
PROCEDURE get_cust (p_custid IN NUMBER, p_cv_cust IN OUT rt_cust)
IS
BEGIN
OPEN p_cv_cust FOR
SELECT customer_id, cust_first_name,phone_numbers,
credit_limit,cust_email FROM customers WHERE customer_id = p_custid;
-- CLOSE p_cv_cust
END get_cust;
END;
SET SERVEROUTPUT ON SIZE UNLIMITED;
declare
cur_orders show_details.rt_order;
v_ordertab cur_orders%ROWTYPE;
begin
show_details.get_order(p_orderid =>2397, p_cv_order =>cur_orders);
LOOP
FETCH cur_orders INTO v_ordertab;
EXIT WHEN cur_orders%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('ORDER_ID: ' || v_ordertab.ORDER_ID || ' ORDER_DATE: ' || v_ordertab.ORDER_DATE || ' ORDER_MODE: ' || v_ordertab.ORDER_MODE || ' CUSTOMER_ID: ' || v_ordertab.CUSTOMER_ID);
END LOOP;
exception
when others then
DBMS_OUTPUT.put_line ('Error Code : ' || SQLCODE);
end;
/
Since you're executing this from SQL Developer, you can use the variable and print commands, which are carried over from SQL*Plus:
variable cur_orders refcursor;
exec show_details.get_order(p_orderid => 2397, p_cv_order => :cur_orders);
print cur_orders
CUR_ORDERS
-------------------------------------------------------------------------------------------------------------------------------------------------
ORDER_ID CUSTOMER_ID ORDER_MODE ORDER_DATE
--------------------------------------- --------------------------------------- --------------------------------------- -------------------------
2397 42 0 03-JAN-15
Notice that you're passing the ref cursor variable as a bind variable, so there is a colon before the name in the call (:cur_order). And you need to run script rather than run statement.
exec is just a shorthand for an anonymous block, so you could do it explicitly if you prefer, but the effect is the same:
var cur_orders refcursor;
begin
show_details.get_order(p_orderid => 2397, p_cv_order => :cur_orders);
end;
/
print cur_orders
You can also get the output in the result grid if you prefer, as shown here, but print is a bit closer to your dbms_output version. Or you can have a wrapper function so you could call query the procedure from a plain SQL call; depends what your end goal is, and if you're just manually executing the procedure to check the output then print may also be good enough.
I am trying to make a script, which will verify my stored procedure's function. However, once I put execute store procedure there, I get this kind of error: PLS-00103: Encountered the symbol "NEW_PRODUCT" when expecting one of the following:
:= . ( # % ; immediate
The symbol ":=" was substituted for "NEW_PRODUCT" to continue.
My script looks like this:
DECLARE
id_unit number;
id_unit_old number;
var_materialid number;
var_processid number;
serial_no varchar(30);
product_name_new varchar(30);
BEGIN
SELECT max(id) INTO id_unit_old
FROM Unit;
execute new_product('NTB', 'Diablo', 'CPU-I7', 'GPU-M800', 'RAM-K2');
SELECT max(id) INTO id_unit
FROM Unit;
IF id_unit > id_unit_old THEN BEGIN
SELECT id_material, id_process, serial_number INTO var_materialid, var_processid, serial_no
FROM Unit
WHERE id = id_unit;
SELECT name INTO product_name_new
FROM Material
WHERE id = var_materialid;
ELSE
RAISE_APPLICATION_ERROR(-20002, 'Insert to table Unit has failed!');
END IF;
END;
Any suggestions what is the problem and how can I solve it? Thanks
Get rid of the execute word right before the new_product word, when you call a PL/SQL procedure from another procedure or from PL/SQL anonymous block you must call it by its name.