I'm getting a 'Procedure created with compilation errors.' - oracle

I'm a beginner to sql and i'm getting a compilation error, can anyone pls guide me with my mistake in the code.
set serveroutput on;
create or replace procedure p1(n in varchar) as
cursor c1 is
select e_name, inv_amount
from employee, investment
where employee.e_id=investment.e_id
and inv_amount=50000;
c c1 %rowtype;
begin
open c1;
dbms_output.put_line('e_name'||"||'inv_amount');
loop
fetch c1 into c;
exit when c1 %notfound;
if(c.inv_amount=n)then
dbms_output.put_line(c.e_name||c.inv_amount);
end if;
end loop;
close c1;
end;
/

I can see some potential errors in your code. Which must be fixed as -
set serveroutput on;
create or replace procedure p1(n in varchar)
AS
cursor c1 is
select e_name,inv_amount
from employee,investment
where employee.e_id=investment.e_id
and inv_amount=50000;
c c1%rowtype; -- No space between cursor and ROWTYPE keyword
begin
open c1;
dbms_output.put_line('e_name'||''||'inv_amount'); -- It must be 2 single quotes instead of 1 double quotes
loop
fetch c1 into c;
exit when c1%notfound; -- Remove space
if(c.inv_amount=n)then
dbms_output.put_line(c.e_name||c.inv_amount);
end if;
end loop;
close c1;
end;
/

You can simplify this quite a lot:
You only care about rows where inv_amount = n, so why not add that as a filter condition in the cursor.
The Cursor FOR loop construction avoids the need to declare everything explicitly.
create or replace procedure p1
( n in number )
as
begin
for r in (
select e_name, inv_amount
from employee e
join investment i on i.e_id = e.e_id
where inv_amount = n
)
loop
dbms_output.put_line(r.e_name || ': ' || r.inv_amount);
end loop;
end p1;
It's also best to write joins using the join keyword.
Note that SQL is the query language and PL/SQL is the programming language, so this a PL/SQL procedure, not SQL.
Regarding "Procedure created with compilation errors", you need to get familiar with how to display and trace compilation errors using your development tool. In SQL*Plus, type
show errors
and you'll get something like this (using your original version of the procedure):
Warning: Procedure created with compilation errors.
SQL> show errors
Errors for PROCEDURE P1:
LINE/COL ERROR
---------- ---------------------------------------------------------------------------------------------------
10/34 PLS-00112: end-of-line in quoted identifier
10/35 PLS-00103: Encountered the symbol "||'inv_amount');" when expecting one of the following:
( - + case mod new null <an identifier>
<a double-quoted delimited-identifier> <a bind variable>
continue avg count current max min prior sql stddev sum
variance execute forall merge standard time timestamp
interval date
<a string literal with character set specification>
<a number> <a single-quoted SQL string> pipe
<an alternatively-quoted string literal with character set specification>
<
You can use the list command to print individual lines, for example line 10 mentioned in the compilation error:
SQL> l 10
10* dbms_output.put_line('e_name'||"||'inv_amount');
or list a range, e.g. lines 8-11:
SQL> l 8 11
8 begin
9 open c1;
10 dbms_output.put_line('e_name'||"||'inv_amount');
11* loop
If you are not using SQL*Plus, you can always query the user_errors dictionary view. However, developer tools like SQL Developer, PL/SQL Developer and Toad highlight compilation errors right in the editor so no special commands are needed.

Related

I am getting an error message in Oracle SQL stored procedure

I am trying the following code
CREATE OR REPLACE PROCEDURE sal2
AS
BEGIN
SELECT sal
FROM emp
END
And I'm getting this error
Error at line 7: PLS-00103: Encountered the symbol "end-of-file" 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
5. from emp
6. return 1
7. END
What I want to do is to get a sal column from emp table.
There are multiple issues with code as following;
create or replace procedure sal2
AS
Lv_var number; -- added variable for holding select value
BEGIN
select sal
Into lv_var -- into is needed in select
from emp; -- you missed this semicolon
-- you must use where clause as into variable can hold single value
-- so you must restrict this query to return only 1 record.
END; -- you missed this semicolon
/
Cheers!!
First you have to put the semicolon at the end of each line and after the END keyword. Then the SELECT statement is also wrong you have to load the result in a variable.
Here is the solution for multiple rows.
CREATE OR REPLACE PROCEDURE sal2
AS
CURSOR c_salaries IS SELECT salary FROM employees;
TYPE t_salaries IS TABLE OF c_salaries%rowtype INDEX BY BINARY_INTEGER;
v_salaries t_salaries;
BEGIN
OPEN c_salaries;
FETCH c_salaries BULK COLLECT INTO v_salaries;
CLOSE c_salaries;
END;
And one for a single row result.
CREATE OR REPLACE PROCEDURE sal2
AS
v_salary employees.salary%rowtype;
BEGIN
SELECT salary INTO v_salary
FROM employees WHERE employee_id = 100;
END;

PLS-00103 error when trying to fetch from a cursor

I'm trying to write a cursor. I try to match the syntax of examples but always getting compile failure on the FETCH statement.
CREATE OR REPLACE PROCEDURE IFSAPP.CLEAR_OLD_PURCHASE_ORDERS (cPlannedDelDate in varchar2) IS
-- cursor to get all the purchase orders's that have lines in released state that
CURSOR c1 IS
SELECT DISTINCT PO.ORDER_NO
FROM PURCHASE_ORDER PO, PURCHASE_ORDER_LINE_NOPART POLN
WHERE PO.ORDER_NO = POLN.ORDER_NO
AND POLN.STATE = 'Released'
AND POLN.PLANNED_DELIVERY_DATE < TO_DATE(cPlannedDelDate, 'DD/MM/YYYY');
BEGIN
DECLARE corder_no varchar2(12);
OPEN c1;
LOOP
FETCH c1 INTO corder_no;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(corder_no);
END LOOP;
CLOSE c1;
END CLEAR_OLD_PURCHASE_ORDERS;
/
LINE/COL ERROR
-------- -----------------------------------------------------------------
17/9 PLS-00103: Encountered the symbol "FETCH" when expecting one of the following:
constant exception <an identifier>
<a double-quoted delimited-identifier> table columns long
double ref char time timestamp interval date binary national
character nchar
21/5 PLS-00103: Encountered the symbol "CLOSE" when expecting one of the following:
end not pragma final instantiable order overriding static
member constructor map
Can anyone see where I am going wrong?
The problem is actually where you're declaring your local variable, and the use of the DECLARE keyword. That's starting a new inner PL/SQL block, but you then have the OPEN etc. without continuing that pattern with a new BEGIN.
You don't need a sub-block though, just move the local variable declaration up before the existing BEGIN, and lose the extra DECLARE:
CREATE OR REPLACE PROCEDURE IFSAPP.CLEAR_OLD_PURCHASE_ORDERS (cPlannedDelDate in varchar2) IS
-- cursor to get all the purchase orders's that have lines in released state that
CURSOR c1 IS
SELECT DISTINCT PO.ORDER_NO
FROM PURCHASE_ORDER PO, PURCHASE_ORDER_LINE_NOPART POLN
WHERE PO.ORDER_NO = POLN.ORDER_NO
AND POLN.STATE = 'Released'
AND POLN.PLANNED_DELIVERY_DATE < TO_DATE(cPlannedDelDate, 'DD/MM/YYYY');
corder_no varchar2(12);
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO corder_no;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(corder_no);
END LOOP;
CLOSE c1;
END CLEAR_OLD_PURCHASE_ORDERS;
/
Incidentally, you should consider using ANSI join syntax, not the ancient comma-separated-FROM clause syntax. And it would be simpler to use an implicit cursor loop:
CREATE OR REPLACE PROCEDURE IFSAPPCLEAR_OLD_PURCHASE_ORDERS (cPlannedDelDate in varchar2) IS
BEGIN
FOR r1 IN (
SELECT DISTINCT PO.ORDER_NO
FROM PURCHASE_ORDER_LINE_NOPART POLN
JOIN PURCHASE_ORDER PO
ON PO.ORDER_NO = POLN.ORDER_NO
WHERE POLN.STATE = 'Released'
AND POLN.PLANNED_DELIVERY_DATE < TO_DATE(cPlannedDelDate, 'DD/MM/YYYY')
) LOOP
DBMS_OUTPUT.PUT_LINE(r1.order_no);
END LOOP;
END CLEAR_OLD_PURCHASE_ORDERS;
/
I'd also generally prefer to have the procedure argument declared as the data type you need, i.e. as a DATE, so you can use that in your query without converting it; and make it the caller's problem to pas the correct data type in.

Trying to assign a single value from a query to a variable... what am i doing wrong?

I am trying to to set a variable (v_flag_id) to the result of a query. I've been looking online at examples and it seems like my formatting/syntax is correct. What am i doing wrong? Thanks in advance.
create or replace PROCEDURE RUN_AGG
is
declare
v_Flag_id Number := select flag_id from flag where flag_tx = 'Processed / Calculated';
CURSOR hours IS
SELECT distinct(HR) as RHR
, submission_value_id
from (
select
v.DATA_DATE,
v.HR,
sv.submission_value_id
from value v
inner join submission_value sv on sv.value_id = v.value_id
where sv.SUBMISSION_VALUE_ID NOT IN (
SELECT SUBMISSION_VALUE_ID FROM VALUE_FLAG WHERE VALUE_FLAG.FLAG_ID = v_Flag_id
);
BEGIN
OPEN hours;
LOOP
FETCH hours into l_hr;
EXIT WHEN hours%NOTFOUND;
AGG_HOURLY_REG_FINAL(l_hr.RHR);
END LOOP;
CLOSE hours;
END RUN_AGG;
The error that I am receiving is as follows:
Error(6,1): PLS-00103: Encountered the symbol "DECLARE" when expecting one
of the following: begin function pragma procedure subtype type <an
identifier> <a double-quoted delimited-identifier> current cursor delete
exists prior external language
Use the following :
CREATE OR REPLACE PROCEDURE RUN_AGG IS
l_rhr VARCHAR2 (100);
l_sub_vl_id VARCHAR2 (100);
CURSOR hours is
SELECT distinct (HR) as RHR, submission_value_id
FROM (SELECT v.DATA_DATE, v.HR, sv.submission_value_id
FROM value_ v
INNER JOIN submission_value sv
ON (sv.value_id = v.value_id)
WHERE sv.SUBMISSION_VALUE_ID NOT IN
(SELECT SUBMISSION_VALUE_ID
FROM VALUE_FLAG
WHERE VALUE_FLAG.FLAG_ID in
(SELECT flag_id
FROM flag
WHERE flag_tx = 'Processed / Calculated')));
BEGIN
OPEN hours;
LOOP
FETCH hours INTO l_rhr, l_sub_vl_id;
EXIT WHEN hours%NOTFOUND;
AGG_HOURLY_REG_FINAL(l_rhr);
END LOOP;
CLOSE hours;
END RUN_AGG;
remove declare
take select flag_id into v_Flag_id from flag where flag_tx =
'Processed / Calculated'; sql in hours cursor's select. So, remove v_Flag_id variable.
return two variables for two columns l_rhr and l_sub_vl_id.
I replaced the name of the table value with value_, since it's a
reserved keyword for oracle.

ORA-01722: invalid number Error - 1

I'm stuck and can't see what the problem is.
I created a procedure with some logic stuff and it compiled successfully, but when I call it in a trigger on my table, it fails with ORA-01722: invalid number.
Any help would be gratefully received.
Here is the procedure:
create or replace Procedure Check_Plants_Fields(
field_id IN number ,
farmer_name IN varchar2,
planting_date IN date DEFAULT sysdate,
planting_amount IN number,
plant_type IN number)
IS
l_plant_type XXLA_PLANTS_TYPE.PLANT_TYPE%type;
l_number_of_months XXLA_PLANTS_SUPPLIERS.NUMBER_MONTHS_TO_CUT%type;
cursor c1 is
SELECT PLANT_TYPE , AMOUNT_
FROM XXLA_PLANTS_TYPE
WHERE PLANT_ID = plant_type;
cursor c2 is
SELECT to_number(MOD(Round(DBMS_RANDOM.Value(1, 8)), 9) + 1)
FROM DUAL;
BEGIN
open c1;
open c2;
fetch c2 into l_number_of_months;
if c1 %notfound then
close c1;
dbms_output.put_line('You dont have this type, please supply it to your store . ' || ' ' || 'thanx.');
end if;
for i in (SELECT PLANT_TYPE , AMOUNT_
FROM XXLA_PLANTS_TYPE
WHERE PLANT_ID = plant_type)
LOOP
if i.AMOUNT_ < 20 then
dbms_output.put_line(i.AMOUNT_ ||' AMOUNT_: '|| i.AMOUNT_);
UPDATE XXLA_PLANTS_SUPPLIERS
SET supplier_id = supplier_id_seq.nextval;
INSERT INTO XXLA_PLANTS_SUPPLIERS
(supplier_id, supplier_name, number_months_to_cut, date_,amount, price_in_KG)
VALUES (supplier_id_seq.nextval, 'Benefits etc',l_number_of_months ,sysdate+1, 80 + i.AMOUNT_,'500$');
end if;
END LOOP i;
commit;
close c2;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered,- '||SQLCODE||' -ERROR- -->'||SQLERRM );
END;
And here is the trigger:
create or replace TRIGGER xxbefor_insert_plants
BEFORE INSERT ON XXLA_PLANT_FIELDS
FOR EACH ROW
BEGIN
Check_Plants_Fields(:NEW.field_id, :NEW.farmer_name, :NEW.planting_date, :NEW.planting_amount, :NEW.plant_type);
END;
Here is the insert that executes the trigger that calls the procedure, but it errors when I run it.
INSERT INTO XXLA_PLANT_FIELDS
(field_id, FARMER_NAME,planting_date,planting_amount,plant_type )
VALUES
(4, 'Test1',sysdate,8,1 (because this parameter it should work its under 20 ));
ORA-01722: invalid number is quite a simple error to understand. It means you are attempting to cast a string to a number datatype but the operation fails because the string contains non-numeric characters.
So what this means is that somewhere in your procedure you have a implicit type conversion. You haven't provided the description of the tables so we can't tell you where the problem happens. You'll have to discover it for yourself.
Two places where it might be:
WHERE PLANT_ID = plant_type if XXLA_PLANTS_TYPE.PLANT_ID is not
numeric
VALUES (... '500$'); if
XXLA_PLANTS_SUPPLIERS.PRICE_IN_KG is not numeric
Incidentally, if you removed that pointless exception handler you would get the default error stack. That would tell you the starting line number of the failing statement, which would really remove a lot of the guesswork from the exercise.

How to do the pattern matching in 'if' condition in oracle stored procedure

CREATE OR REPLACE PROCEDURE get_pop1
AS
ROUTERNAME_V varchar2(100);
BEGIN
SELECT TRAFFIC_CUST_ID
INTO ROUTERNAME_V
FROM INTERFACE_ATTLAS
WHERE rownum < 2;
IF CHARINDEX('RNS',ROUTERNAME_V) > 0
dbms_output.put_line(routername_v);
ELSE
PRINT 'It doesn''t Contain'
END;
/* HERE I AM TRYING TO DISPLAY THE RECORDS ONLY IT STARTS WITH 'RNS' STRING
I am getting error like :
10/3 PLS-00103: Encountered the symbol "DBMS_OUTPUT" when expecting
one of the following:
* & - + / at mod remainder rem then and or
|| multiset
The symbol "*" was substituted for "DBMS_OUTPUT" to continue.
10/37 PLS-00103: Encountered the symbol ";" when expecting one of the
following:
. ( * % & - + / at mod remainder rem then
and or || */
CHARINDEX and PRINT are not Oracle functions. Unless you've defined those yourself as wrappers, you'll need to switch to functions Oracle does recognise. You're also missing THEN and END IF.
CREATE OR REPLACE PROCEDURE get_pop1
AS
ROUTERNAME_V varchar2(100);
BEGIN
SELECT TRAFFIC_CUST_ID
INTO ROUTERNAME_V
FROM INTERFACE_ATTLAS
WHERE rownum < 2;
IF INSTR(ROUTERNAME_V, 'RNS') > 0 THEN
dbms_output.put_line(routername_v);
ELSE
dbms_output.put_line('It doesn''t Contain');
END IF;
END;
/
You said you wanted the string to start with RNS, and INSTR will find it anywhere; you'd need to test that it returns exactly 1, not > 0.
You could also do:
IF ROUTERNAME_V LIKE 'RNS%' THEN
DBMS_OUTPUT puts the text into a buffer that something else can then retrieve, so you'll only see anything if your client is expecting this when it is executed (not just when it is compiled); e.g. with set serveroutput on in SQL*Plus, or by opening the DBMS Output panel in SQL Developer. You generally shouldn't rely on that being available.
set serveroutput on
exec get_pop1;
The get in the procedure name suggests that maybe you really want a function that returns the value, or the fixed string if it doesn't match your pattern.
CREATE OR REPLACE FUNCTION get_pop2
RETURN VARCHAR2 AS
ROUTERNAME_V varchar2(100);
BEGIN
SELECT TRAFFIC_CUST_ID
INTO ROUTERNAME_V
FROM INTERFACE_ATTLAS
WHERE rownum < 2;
IF ROUTERNAME_V LIKE 'RNS%' THEN
RETURN(routername_v);
ELSE
RETURN('It doesn''t Contain');
END IF;
END;
/
Then you can do:
select get_pop2 from dual;
It might be worth noting that you're selecting an arbitrary row from your table. If it has more than one row there is nothing to determine which one you get; the same query against the same data could get a different row back. You need a filter and/or an order by to control which you get, e.g. the most recent record if they are time-stamped.
CREATE OR REPLACE PROCEDURE get_pop1
AS
ROUTERNAME_V varchar2(100);
BEGIN
SELECT TRAFFIC_CUST_ID
INTO ROUTERNAME_V
FROM INTERFACE_ATTLAS
WHERE TRAFFIC_CUST_ID LIKE '%RNS%' and rownum < 2;
IF CHARINDEX('RNS',ROUTERNAME_V) > 0 THEN
dbms_output.put_line(routername_v);
END;
I'm not sure you want the String RNS at the beginning or not, you may want to replace '%RNS%' by 'RNS%'.

Resources