Oracle select query error inside procedure [duplicate] - sql

This question already has answers here:
Oracle Procedure error (PLS-00428)
(5 answers)
Closed 8 years ago.
I'm getting error while I'm running select query inside procedure. Error print as follow:
[Error] PLS-00428 (24: 9): PLS-00428: an INTO clause is expected in this SELECT statement
CREATE OR REPLACE PACKAGE BODY PACK_EMP
IS
PROCEDURE find_employee(
P_ID NUMBER,
P_ERR OUT VARCHAR2
)
IS
BEGIN
IF P_ID IS NULL THEN
SELECT * FROM EMPLOYEE WHERE ID = P_ID
ELSE
P_ERR := 'An error occured on database!!';
END IF;
EXCEPTION
WHEN OTHERS THEN
P_ERR := SQLERRM;
END;
END;

CREATE OR REPLACE PACKAGE BODY PACK_EMP
IS
PROCEDURE find_employee(
P_ID NUMBER,
P_ERR OUT VARCHAR2,
V_VAL OUT VARCHAR
)
IS
BEGIN
IF P_ID IS NULL THEN
SELECT FIRTSNAME ||' '||LASTNAME INTO V_VAL FROM EMPLOYEE WHERE ID = P_ID
ELSE
P_ERR := 'An error occured on database!!';
END IF;
EXCEPTION
WHEN OTHERS THEN
P_ERR := SQLERRM;
END;
END;

Use a rowtype. Also I think you meant to say "IF P_ID IS NOT NULL THEN..." because if it is null then your select will never work.
CREATE OR REPLACE PACKAGE BODY PACK_EMP
IS
PROCEDURE find_employee(
P_ID NUMBER,
P_ERR OUT VARCHAR2
)
IS
empRec employee%rowtype; /* ADD THIS LINE */
BEGIN
IF P_ID IS NOT NULL THEN
SELECT * into empRec FROM EMPLOYEE WHERE ID = P_ID;
--now you can reference the columns like this: empRec.id
ELSE
P_ERR := 'An error occured on database!!';
END IF;
EXCEPTION
WHEN OTHERS THEN
P_ERR := SQLERRM;
END;
END;

Related

PLS-00103: Encountered the symbol "CREATE" for package

I have to execute a SQL file (I do not have much idea of SQL, I just have to execute it) but there is an error I do not understand:
Errors: check compiler log
Errors for PACKAGE USER1.TST_MAI_FILTER:
LINE/COL ERROR
29/1 PLS-00103: Encountered the symbol "CREATE"
This is the PACKAGE USER1.TST_MAI_FILTER:
CREATE OR REPLACE PACKAGE TST_MAI_FILTER IS
FUNCTION TRADE_TYPE
RETURN NUMBER;
FUNCTION ORDER_TYPE
RETURN NUMBER;
FUNCTION MRKT_EVT_TYPE
RETURN NUMBER;
FUNCTION DAILY_DATA_TYPE
RETURN NUMBER;
PROCEDURE log_mai_filter(p_run_id NUMBER, p_config_id NUMBER);
PROCEDURE is_valid_filter
(p_mai_class_id IN NUMBER,
p_type_id IN NUMBER,
v_where CLOB);
END TST_MAI_FILTER;
/
I am using Oracle SQL Developer (Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production).
EDIT: This is line 29:
CREATE SEQUENCE S_TRD START WITH 1 INCREMENT BY 1 MINVALUE 1 CACHE 20 NOORDER;
and this is the rest of the package but it does not get until there since the developer stops after this error:
CREATE OR REPLACE PACKAGE BODY TST_MAI_FILTER IS
FUNCTION TRADE_TYPE
RETURN NUMBER
IS
BEGIN
RETURN 1;
END;
FUNCTION ORDER_TYPE
RETURN NUMBER
IS
BEGIN
RETURN 2;
END;
FUNCTION MRKT_EVT_TYPE
RETURN NUMBER
IS
BEGIN
RETURN 3;
END;
FUNCTION DAILY_DATA_TYPE
RETURN NUMBER
IS
BEGIN
RETURN 4;
END;
PROCEDURE log_mai_filter(p_run_id NUMBER, p_config_id NUMBER)
IS
v_mesg VARCHAR2(4000 BYTE) := NULL;
BEGIN
INSERT INTO mai_filter_log (run_id, mai_query_id, sql_query, config_id, type_id, mai_class_id)
SELECT p_run_id, mai_query_id, sql_query, config_id, type_id, mai_class_id
FROM mai_filter
WHERE config_id = p_config_id;
LOG_INFO(p_run_id, 'I', 'RUN_LOG: Log mai_filter: ' || SQL%ROWCOUNT );
EXCEPTION
WHEN OTHERS THEN
v_mesg := 'An error has occured when executing log_mai_filter - ' || SQLCODE || ' -ERROR- ' || SQLERRM;
raise_application_error(-20085, v_mesg);
LOG_INFO(p_run_id, 'E', v_mesg);
END;
PROCEDURE is_valid_filter
(p_mai_class_id IN NUMBER,
p_type_id IN NUMBER,
v_where CLOB) IS
v_tbl VARCHAR2(400 BYTE) := NULL;
BEGIN
SELECT type_name INTO v_tbl
FROM mai_filter_type
WHERE type_id = p_type_id;
EXECUTE IMMEDIATE 'SELECT run_id FROM ' || v_tbl || ' WHERE run_id = 0 AND '|| v_where;
END;
END TST_MAI_FILTER;
/

PL/SQL Error PLS-00103 - Encountered symbol xxxx when expecting yyyy

I know these errors are most often caused by typos; that's what I've been finding at least. If my problem is a typo, I cannot see it after ~30 minutes of looking, it's driving me crazy.
My question is: am I doing something fundamentally wrong, or can you see a typo?
PL/SQL:
CREATE OR REPLACE PROCEDURE Replenish_Stock(p_id VARCHAR2, n INT)
AS
no_such_id EXCEPTION;
CURSOR pc IS
SELECT Product_ID FROM Products;
BEGIN
IF p_id IN pc THEN
UPDATE Products
SET Stock_Level = Stock_Level + n
WHERE product_id = p_id;
ELSE
RAISE no_such_id;
END IF;
EXCEPTION
WHEN INVALID_NUMBER THEN
DBMS_OUTPUT.PUT_LINE('Bad integer input, ignoring procedure call.');
WHEN no_such_id THEN
DBMS_OUTPUT.PUT_LINE('Bad Product id, ignoring procedure call.');
END;
/
Error code:
Error(7,14): PLS-00103: Encountered the symbol "PC" when expecting one of the following: (
Thanks for any help.
Your usage of IN and CURSOR is not right. the below should work for you. You can just use SQL%ROWCOUNT to see if the update query impact any rows in the table.
CREATE OR REPLACE PROCEDURE Replenish_Stock(p_id VARCHAR2, n INT)
AS
no_such_id EXCEPTION;
Rows_Updated NUMBER;
BEGIN
UPDATE Products
SET Stock_Level = Stock_Level + n
WHERE product_id = p_id;
IF( SQL%ROWCOUNT = 0) THEN
RAISE no_such_id;
END IF;
EXCEPTION
WHEN INVALID_NUMBER THEN
DBMS_OUTPUT.PUT_LINE('Bad integer input, ignoring procedure call.');
WHEN no_such_id THEN
DBMS_OUTPUT.PUT_LINE('Bad Product id, ignoring procedure call.');
END;
/

Function returned without value

This is the function which I designed. It got complied successfully
CREATE OR REPLACE FUNCTION "F_CHECK"
(
p_id IN VARCHAR2
p_name IN VARCHAR2)RETURN VARCHAR2
is
v_id VARCHAR2;
v_name VARCHAR2;
cnt pls_integer;
BEGIN
IF id IS NULL THEN
RETURN NULL;
END IF;
SELECT COUNT(*) INTO cnt from emp_new where id = p_id;
IF (cnt > 0) THEN
SELECT id, name INTO v_id, v_name from emp_new where id=p_id;
IF (v_id is null and p_id is null and v_name is null and p_name is null) THEN
return NULL;
ELSE
IF (v_name =trunc(p_name)) then
return NULL;
else
insert into employees values(p_id,p_name,sysdate);
end if;
end if;
end if;
exception
when DUP_VAL_ON_INDEX THEN
raise application error (-20001, 'NAME EXISTS UNDER DIFFERENT ID');
END F_CHECK;
But I'm not getting the expected result, when I execute the function
select F_CHECK(1,1) from dual;
ERROR I'M getting is:
SQL EEROR: ORA-06503: PL/SQL : FUNCTION RETURNED WITHOUT VALUE
You must return a value when the execution flow reaches (around line 22)
...
else
insert into employees values(p_id,p_name,sysdate);
end if;
...
In this case, the function does not return a value which is expected by the caller, hence the error.
You can instruct the PL/SQL compiler to warn you about such code (and other problems) with
ALTER SESSION SET PLSQL_WARNINGS='ENABLE:ALL'; prior to compilation.
One of the possible causes of exceptions that you will get when you run this code is: If your select into didn't return a value, you will get an exception, an nu-handled exception
Even though you have a return NULL in the end of the function, but still you need to catch all the exceptions that might occur
The area where you need to take care of is:
SELECT id, name INTO v_id, v_name from emp_new where id=p_id;
Surround it by Begin ... EXCEPTION WHEN NO_DATA_FOUND THEN ... END; block
Also, your insert statement might cause an exception if you violated some constraints on your table, so you might need to handle that also
Have a look at Error Handling in Oracle
Below is your updated code, also fixed code regarding the extra parenthesis
Edited
CREATE OR REPLACE FUNCTION F_CHECK
(
P_ID EMP_NEW.ID%TYPE,
P_NAME EMP_NEW.NAME%TYPE
)
RETURN VARCHAR2 IS
V_ID EMP_NEW.ID%TYPE;
V_NAME EMP_NEW.NAME%TYPE;
CNT NUMBER;
BEGIN
--IF ID IS NULL THEN
-- What is ID ?? is it P_ID
--Changed below
IF P_ID IS NULL THEN
RETURN 'Error: Add Value For Id';
END IF;
IF P_NAME IS NULL THEN
RETURN 'Error: Add Value For Name';
END IF;
SELECT
COUNT(*) INTO CNT FROM EMPLOYEES
WHERE ID = P_ID;
IF (CNT > 0) THEN
SELECT
ID, NAME INTO V_ID, V_NAME
FROM
EMP_NEW
WHERE
ID=P_ID;
----------------------------------------------------------------------------------------
--IF V_ID IS NULL AND P_ID IS NULL AND V_NAME IS NULL AND P_NAME IS NULL THEN
--The code above will always evaluate to False because P_ID at this stage is not null!
--Also, if P_Name must have a value, check it at the begining along with the ID, not here
----------------------------------------------------------------------------------------
IF V_ID IS NULL AND V_NAME IS NULL THEN
RETURN 'Error: Not found details';
ELSE
--Details are found
IF (V_NAME = TRUNC(P_NAME)) THEN
RETURN 'Name already assigned to this id';
ELSE --Its a new name, add it
INSERT INTO EMPLOYEES VALUES(P_ID,P_NAME,SYSDATE);
--Make sure your columns are only three and in the correct order as the Values specified
END IF;
END IF;
END IF;
RETURN 'Ok, added';
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
raise application error (-20001, 'NAME EXISTS UNDER DIFFERENT ID');
END F_CHECK;
A function MUST ALWAYS RETURN a VALUE of proper data type. Else, it would throw the following error:
ORA-06503: PL/SQL: Function returned without value
Cause: A call to PL/SQL function completed, but no RETURN statement was executed.
Action: Rewrite PL/SQL function, making sure that it always returns a value of a proper type.
Read ORA-06503: PL/SQL: Function returned without value
DB version : 11.2.0.2.0
Let’s see the various scenarios of this error :
Without a RETURN statement in the function body and without exception handler(most stupid way):
SQL> set serveroutput on
SQL> CREATE OR REPLACE FUNCTION f_test(i_val NUMBER)
2 RETURN NUMBER AS
3 o_val NUMBER;
4 BEGIN
5 SELECT 100 / i_val
6 INTO o_val
7 FROM DUAL;
8 END;
9 /
Function created
SQL> select f_test(100) from dual;
select f_test(100) from dual
ORA-06503: PL/SQL: Function returned without value
ORA-06512: at "F_TEST", line 8
Now, in the above code, the mathematical logic was correct, hence there was no SQL error to override the PL/SQL error. Let’s see how ORA-01476 will override the ORA-06503 error.
SQL> CREATE OR REPLACE FUNCTION f_test(i_val NUMBER)
2 RETURN NUMBER AS
3 o_val NUMBER;
4 BEGIN
5 SELECT 100 / i_val
6 INTO o_val
7 FROM DUAL;
8 END;
9 /
Function created
SQL> select f_test(0) from dual;
select f_test(0) from dual
ORA-01476: divisor is equal to zero
ORA-06512: at "F_TEST", line 5
Well, that’s quite obvious, isn’t it?
Without a RETURN statement in the exception handler(most common mistake):
SQL> CREATE OR REPLACE FUNCTION f_test(i_val NUMBER)
2 RETURN NUMBER AS
3 o_val NUMBER;
4 BEGIN
5 SELECT 100 / i_val
6 INTO o_val
7 FROM DUAL;
8
9 RETURN o_val;
10
11 EXCEPTION
12 WHEN OTHERS THEN
13 NULL;
14 END;
15 /
Function created
SQL> select f_test(0) from dual;
select f_test(0) from dual
ORA-06503: PL/SQL: Function returned without value
ORA-06512: at "F_TEST", line 14
Now let’s put a RETURN statement at required places and the code should work fine without any error:
SQL> CREATE OR REPLACE FUNCTION f_test(i_val NUMBER)
2 RETURN NUMBER AS
3 o_val NUMBER;
4 BEGIN
5 SELECT 100 / i_val
6 INTO o_val
7 FROM DUAL;
8
9 RETURN o_val;
10
11 EXCEPTION
12 WHEN OTHERS THEN
13 DBMS_OUTPUT.PUT_LINE('Came inside Exception handler');
14 RETURN 0;
15 END;
16 /
Function created
SQL> select f_test(0) from dual;
F_TEST(0)
0
Came inside Exception handler
Bottom line is that :
A function MUST ALWAYS RETURN a value of proper datatype, no matter from the body or exception.
We must do something with the error not just return junk. We must RAISE/log error and handle it, do something about the error so that underlying process has no impact.
Lastly, not to forget, EXCEPTION WHEN OTHERS THEN NULL; –> is itself a bug in the code waiting for its chance to break the code.

Simple PL/SQL to check if table exists is not working

I'm in the process of converting some stored procedures from Sybase TSQL to Oracle PL/SQL and I've already come across a problem which I'm struggling to resolve!
The below code will not run:
DECLARE
t INT := 0;
t_error EXCEPTION;
v_line VARCHAR2(100);
BEGIN
SELECT COUNT(*) INTO t FROM user_tables WHERE table_name = UPPER('tbl_BSUK_PriceIssue');
IF t = 1 THEN
EXECUTE IMMEDIATE 'DROP TABLE tbl_BSUK_PriceIssue';
t := 0;
SELECT COUNT(*) INTO t FROM user_tables WHERE table_name = UPPER('tbl_BSUK_PriceIssue');
IF t = 1 THEN
RAISE t_error;
END IF;
END IF;
EXCEPTION
WHEN t_error THEN
v_line := '<<< FAILED DROPPING table tbl_BSUK_PriceIssue >>>';
dbms_output.put_line (v_line);
WHEN OTHERS THEN
v_line := '<<< Unknown Error >>>';
dbms_output.put_line (v_line);
END;
END;
I get the following error message, what am I doing wrong?!
Error starting at line : 17 in command - DECLARE
t INT := 0; t_error EXCEPTION; v_line VARCHAR2(100);
BEGIN
SELECT COUNT(*) INTO t FROM user_tables WHERE table_name =
UPPER('tbl_BSUK_PriceIssue');
IF t = 1 THEN EXECUTE IMMEDIATE 'DROP TABLE tbl_BSUK_PriceIssue';
t := 0; SELECT COUNT(*) INTO t FROM user_tables WHERE table_name =
UPPER('tbl_BSUK_PriceIssue'); IF t = 1 THEN
RAISE t_error; END IF; END IF;
EXCEPTION WHEN t_error THEN v_line := '<<< FAILED DROPPING table
tbl_BSUK_PriceIssue >>>'; dbms_output.put_line (v_line); WHEN
OTHERS THEN
v_line := '<<< Unknown Error >>>';
dbms_output.put_line (v_line); END;
END; Error report - ORA-06550: line 30, column 1: PLS-00103: Encountered the symbol "END"
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
I'm actually trying to replace the following TSQL with a PL/SQL version:
-- Create temp table for relevant trev_id's
IF OBJECT_ID('dbo.tbl_BSUK_PriceIssue') IS NOT NULL
BEGIN
DROP TABLE dbo.tbl_BSUK_PriceIssue
IF OBJECT_ID('dbo.tbl_BSUK_PriceIssue') IS NOT NULL
PRINT '<<< FAILED DROPPING TABLE dbo.tbl_BSUK_PriceIssue >>>'
ELSE
PRINT '<<< DROPPED TABLE dbo.tbl_BSUK_PriceIssue >>>'
END
go
try to remove END; in this section
WHEN OTHERS THEN
v_line := '<<< Unknown Error >>>';
dbms_output.put_line (v_line);
END;
UPD. Actually, you can do it a bit shorter, no need to check if table exists after drop
declare
eTableNotExists exception;
pragma exception_init(eTableNotExists, -00942);
begin
EXECUTE IMMEDIATE 'DROP TABLE tbl_BSUK_PriceIssue';
dbms_output.put_line('<<< DROPPED TABLE dbo.tbl_BSUK_PriceIssue >>>');
exception
when eTableNotExists then null
when others then
dbms_output.put_line ('<<< Unknown Error >>>' || sqlerrm);
end;
/
I don't know about the error, but you can do what you want in a fraction of the code. You don't need the count variable if you use EXISTS() and you don't need EXECUTE IMMEDIATE because you don't have variable data in the command:
IF 1 = (SELECT 1 FROM user_tables WHERE table_name = 'TBL_BSUK_PRICEISSUE') THEN
DROP TABLE tbl_BSUK_PriceIssue;
IF 1 = (SELECT 1 FROM user_tables WHERE table_name = 'TBL_BSUK_PRICEISSUE') THEN
RAISE EXCEPTION;
END IF;
END IF;

How to get NULL condition checks for PL/SQL associative array DS

I have the following code snippet and I would like to know how to check for existence of an entry in the associative array
set serveroutput on;
DECLARE
TYPE per_form_metric IS record
(
output_achieved_itd NUMBER,
output_achieved_ptd NUMBER
);
TYPE per_form_metrics_tbl IS TABLE OF per_form_metric INDEX BY VARCHAR2(10) ;
TYPE interval_number_tbl IS TABLE OF per_form_metrics_tbl INDEX BY VARCHAR2(10) ;
TYPE ms_output_tbl IS TABLE OF interval_number_tbl INDEX BY VARCHAR2(100) ;
g_ms_output_tbl ms_output_tbl ;
l_per_f_rec per_form_metric;
l_per_f_tbl per_form_metrics_tbl;
l_per_int_tbl interval_number_tbl;
l_ms_out_tbl ms_output_tbl;
BEGIN
l_per_f_rec.output_achieved_itd := 1000;
l_per_f_rec.output_achieved_ptd := 1000;
l_per_f_tbl('Period 1') := l_per_f_rec;
l_per_int_tbl('Interval 1') := l_per_f_tbl;
l_ms_out_tbl('1') := l_per_int_tbl;
-- Now get me the output_achieved_itd for 1 , Interval 1, Period 1
dbms_output.put_line(l_ms_out_tbl('1')('Interval 1')('Period 1').output_achieved_itd);
dbms_output.put_line(l_ms_out_tbl('2')('Interval 1')('Period 1').output_achieved_itd);
END;
The output for this code is as below
Error report:
ORA-01403: no data found
ORA-06512: at line 31
01403. 00000 - "no data found"
*Cause:
*Action:
1000
How can I check if
l_ms_out_tbl('2')('Interval 1')('Period 1').output_achieved_itd
exists?
I would like to say something like
IF (l_ms_out_tbl('2')('Interval 1')('Period 1').output_achieved_itd IS NOT NULL) THEN
do something awesome
ELSE
continue wallowing
END IF;
Instead of evaluating for nullality, evaluate for existence:
IF (l_ms_out_tbl.EXISTS('2'))
THEN
IF (l_ms_out_tbl('2').EXISTS('Interval 1'))
THEN
IF (l_ms_out_tbl('2')('Interval 1').EXISTS('Period 1'))
THEN
null; --do something awesome
END IF;
END IF;
ELSE
null; --continue wallowing
END IF;
or catch NO_DATA_FOUND:
begin
dbms_output.put_line(l_ms_out_tbl('2')('Interval 1')('Period 1').output_achieved_itd)
-- did something awesome
exception
when NO_DATA_FOUND then
null;
-- continue wallowing
end;
Use exists collection method. E.g.:
declare
type foo_t is table of varchar2(20) index by varchar2(20);
v_foos foo_t;
begin
v_foos('FOO') := 'this is foo';
if v_foos.exists('FOO') then
dbms_output.put_line('exists');
else
dbms_output.put_line('not exists');
end if;
end;
/
How to apply that to nested associative arrays is left to the OP :)
See also:
PL/SQL - Working with a string!
Why is this check for null associative array in PL/SQL failing?