Getting pl/sql statement ignored error when writing a procedure - oracle

create or replace PROCEDURE CREATE_DEL_DEPT <br>
(
PARAM1 IN VARCHAR2 Default '%',
PARAM2 IN VARCHAR2 Default '%',
PARAM3 IN BOOLEAN Default True
) AS
PRAGMA AUTONOMOUS_TRANSACTION;
CURSOR Employees IS
Select Employee_ID, First_name, Last_Name
From HR.employees Where Department_ID = PARAM2;
BEGIN
For Employee_ID in Employees LOOP
if Department_ID = 20 then
DBMS_OUTPUT.PUT_LINE ('test');
elsif Department_ID = 30 then
DBMS_OUTPUT.PUT_LINE ('test1');
else
DBMS_OUTPUT.PUT_LINE ('else test');
end if;
END LOOP;
END;
I'm getting following error. Line 14 is where starting of 'If' statement is
Error(14,9): PL/SQL: Statement ignored

You need to refer to department_id when selecting from the table in the cursor
CREATE OR REPLACE PROCEDURE create_del_dept
(
PARAM1 IN VARCHAR2 Default '%',
PARAM2 IN VARCHAR2 Default '%',
PARAM3 IN BOOLEAN Default True
) AS
PRAGMA AUTONOMOUS_TRANSACTION;
CURSOR Employees IS
Select Employee_ID, First_name, Last_Name,department_id
From HR.employees Where Department_ID = PARAM2;
BEGIN
for rec in employees LOOP
IF
rec.department_id = 20
THEN
dbms_output.put_line('test');
ELSIF rec.department_id = 30 THEN
dbms_output.put_line('test1');
ELSE
dbms_output.put_line('else test');
END IF;
END LOOP;
END;
/
By the way, you may simplify your code avoiding a cursor definition by using implicit cursor loop.
for rec in ( Select Employee_ID, First_name, Last_Name,department_id
From HR.employees Where Department_ID = PARAM2
) loop

Related

Getting error 'wrong number or types of arguments in call to 'DISP_EMP_DETAILS' while calling a stored procedure in PL/SQL

The requirement is that I have to give the employee number and fetch the email and salary of that particular employee. Below is the PL/SQL code
CREATE OR REPLACE PROCEDURE p (
iempno IN NUMBER ,
outemail out varchar2 ,
outsalary out number
) IS
lv_count NUMBER(10);
BEGIN
SELECT count(*) into lv_count
from hr.employees
WHERE employee_id = iempno;
IF lv_count = 0
then
RAISE_APPLICATION_ERROR(-20001,'Employee_id ' ||iempno||' does not exist');
ELSE
EXECUTE IMMEDIATE 'Select email, salary from t where empid = '||iempno||' ' into outemail, outsalary;
dbms_output.put_line( ' Employee '||iempno||' has email: '||outemail||' and salary '||outsalary||' ');
END IF;
END;
/
I am executing using exec DISP_EMP_DETAILS(198);
I would do something like this, as you don't need any out parameter.
Let me show you a demo
Test Data
SQL> create table t ( empid number , email varchar2(100) , salary number) ;
Table created.
SQL> insert into t values ( 1 , 'a#gmail.com' , 1000 ) ;
1 row created.
SQL> insert into t values ( 2, 'b#gmail.com' , 2000 ) ;
1 row created.
SQL> commit ;
SQL> desc t
Name Null? Type
----------------------------------------- -------- ----------------------------
EMPID NUMBER
EMAIL VARCHAR2(100)
SALARY NUMBER
SQL>
Now, let's simplify your code
Procedure
CREATE OR REPLACE PROCEDURE p (
iempno IN NUMBER
) IS
lv_count NUMBER(10);
semail t.email%type;
ssalary t.salary%type;
BEGIN
SELECT count(*) into lv_count
from t
WHERE empid = iempno;
IF lv_count = 0
then
RAISE_APPLICATION_ERROR(-20001,'Employee_id ' ||iempno||' does not exist');
ELSE
EXECUTE IMMEDIATE 'Select email, salary from t where empid = '||iempno||' ' into semail, ssalary;
dbms_output.put_line( ' Employee '||iempno||' has email: '||semail||' and salary '||ssalary||' ');
END IF;
END;
/
Testing
SQL> set serveroutput on
SQL> exec p ( iempno => 1 ) ;
Employee 1 has email: a#gmail.com and salary 1000
PL/SQL procedure successfully completed.
SQL> exec p ( iempno => 3 ) ;
BEGIN p ( iempno => 3 ) ; END;
*
ERROR at line 1:
ORA-20001: Employee_id 3 does not exist
ORA-06512: at "TEST1.P", line 14
ORA-06512: at line 1
Summary
You don't need in this case out parameters, as you only want to show values.
When you use execute immediate of a select, the output has to go somewhere, therefore I put two variables to get the output.
But you have to filter the select to give you the record you want, by the employee that you know it exists.
I use raise_application_error because it fits better your scenario. If the employee_id does not exist, you can exit the execution in that moment. exception variables are used for controlling different types of errors that you can manage later on in the exception block, applying logic over them, etc.
UPDATE
If you insist in using out parameters
CREATE OR REPLACE PROCEDURE p (
iempno IN NUMBER ,
outemail out varchar2 ,
outsalary out number
) IS
lv_count NUMBER(10);
BEGIN
SELECT count(*) into lv_count
from t
WHERE empid = iempno;
IF lv_count = 0
then
RAISE_APPLICATION_ERROR(-20001,'Employee_id ' ||iempno||' does not exist');
ELSE
EXECUTE IMMEDIATE 'Select email, salary from t where empid = '||iempno||' ' into outemail, outsalary;
dbms_output.put_line( ' Employee '||iempno||' has email: '||outemail||' and salary '||outsalary||' ');
END IF;
END;
/
Run
SQL> declare
2 amount number;
3 email varchar2(100);
4 begin
5 p ( iempno => 1 , outemail => email , outsalary => amount );
6 end;
7 /
Employee 1 has email: a#gmail.com and salary 1000
PL/SQL procedure successfully completed.
In your case
set serveroutput on
declare
amount number;
email varchar2(100);
begin
<<procedure_owner>>.<<procedure_name>> ( iempno => 198, outemail => email, outsalary => amount );
end;
/

How to pass string of comma-separated numbers to stored procedure in condition for numeric field?

I have a stored procedure like below where multiple employee IDs will be passed as comma-separated value (multiple IDs). It is throwing error as "ORA-01722: invalid number". I know it's because of passing varchar2 variable for the numeric ID column. But is there any way we can achieve this simply?
create or replace PROCEDURE Fetch_Emp_Name(Emp_id in varchar2)
IS
BEGIN
select Name from EMP where id in (emp_id);
END;
You can use dynamic sql.
create or replace PROCEDURE Fetch_Emp_Name(emp_id in varchar2) IS
v_result varchar2;
begin
execute immediate
'select Name from EMP where id in (' || 'emp_id' || ')'
into
v_result;
end;
Also you can use package dbms_sql for dynamic sql.
Update
Another approach. I think may be better.
create or replace PROCEDURE Fetch_Emp_Name(emp_id in varchar2) IS
v_result varchar2;
begin
select
Name
from
EMP
where
id in
(
select
to_number(regexp_substr(emp_id, '[^,]+', 1, level))
from
dual
connect by regexp_substr(emp_id, '[^,]+', 1, level) is not null
);
exception
when no_data_found then
-- error1;
when too_many_rows then
-- error2;
end;
Sorry for before, I did not get the question in the right way. If you get a lot of IDs as different parameters, you could retrieve the list of names as an string split by comma as well. I put this code where I handled by regexp_substr the name of different emp_ids you might enter in the input parameter.
Example ( I am assuming that the IDs are split by comma )
create or replace PROCEDURE Fetch_Emp_Name(p_empid in varchar2) IS
v_result varchar2(4000);
v_append emp.name%type;
v_emp emp.emp_id%type;
counter pls_integer;
i pls_integer;
begin
-- loop over the ids
counter := REGEXP_COUNT(p_empid ,'[,]') ;
--dbms_output.put_line(p_empid);
if counter > 0
then
i := 0;
for r in ( SELECT to_number(regexp_substr(p_empid,'[^,]+',1,level)) as mycol FROM dual CONNECT BY LEVEL <= REGEXP_COUNT(p_empid ,'[,]')+1 )
loop
--dbms_output.put_line(r.mycol);
v_emp := r.mycol ;
select name into v_append from emp where emp_id = v_emp;
if i < 1
then
v_result := v_append ;
else
v_result := v_result ||','|| v_append ;
end if;
i := i + 1;
end loop;
else
v_emp := to_number(p_empid);
select name into v_result from emp where emp_id = v_emp;
end if;
dbms_output.put_line(v_result);
exception
when no_data_found
then
raise_application_error(-20001,'Not Employee found for '||v_emp||' ');
when too_many_rows
then
raise_application_error(-20002,'Too many employees for id '||v_emp||' ');
end;
Test
SQL> create table emp ( emp_id number, name varchar2(2) ) ;
Table created.
SQL> insert into emp values ( 1 , 'AA' );
1 row created.
SQL> insert into emp values ( 2 , 'BB' ) ;
1 row created.
SQL> commit;
SQL> insert into emp values ( 3 , 'CC' ) ;
1 row created.
SQL> select * from emp ;
EMP_ID NA
---------- --
1 AA
2 BB
3 CC
SQL> exec Fetch_Emp_Name('1') ;
AA
PL/SQL procedure successfully completed.
SQL> exec Fetch_Emp_Name('1,2,3') ;
AA,BB,CC
PL/SQL procedure successfully completed.
SQL>

too many values error while using rowtype in procedure

CREATE OR replace PACKAGE emp_pkg
AS
PROCEDURE find_emp1(
c_id IN employees.employee_id%TYPE);
END emp_pkg;
/
CREATE OR replace PACKAGE BODY emp_pkg
AS
PROCEDURE Find_emp1(c_id IN employees.employee_id%TYPE)
IS
v_row employees%ROWTYPE;
BEGIN
SELECT first_name,
employee_id,
hire_date
INTO v_row
FROM employees
WHERE employee_id = c_id;
dbms_output.Put_line('ID:'
|| v_row.employee_id);
dbms_output.Put_line('NAME:'
||v_row.first_name);
dbms_output.Put_line('HIRE_DATE:'
|| v_row.hire_date);
END find_emp1;
END emp_pkg;
/
I think you have a mismatch between the 3 values in the select statement and the number of columns in your table. What are the table columns?

What considerations Do You have about my PLSQL package?

I had a little doubts about my code but yesterday I finally understood some points about to how to start coding my final package project. I share this code with the purpose if You want suggest me some change to perform or anything about my package I will appreciate you.
CREATE OR REPLACE PACKAGE BODY emp_upd_pkg IS
-- Function to update commission of employee --
FUNCTION comm_upd(
p_empid employees.employee_id%TYPE)
RETURN employees.commission_pct%TYPE
IS
v_oldcomm employees.commission_pct%TYPE;
v_newcomm employees.commission_pct%TYPE;
BEGIN
-- Valid parameter --
SELECT commission_pct
INTO v_oldcomm
FROM employees
WHERE employee_id = p_empid;
IF
v_oldcomm IS NOT NULL THEN
UPDATE employees
SET commission_pct = commission_pct * 1.1
WHERE employee_id = p_empid
RETURNING commission_pct
INTO v_newcomm;
RETURN v_newcomm;
ELSE
/*UPDATE employees
SET commission_pct = 0.1
WHERE employee_id = p_empid
RETURNING commission_pct
INTO v_newcomm;
RETURN v_newcomm;*/
RETURN (0);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN (0);
END comm_upd;
-- Function to update salary of employee --
FUNCTION sal_upd(
p_empid employees.employee_id%TYPE)
RETURN employees.salary%TYPE
IS
v_oldsal employees.salary%TYPE;
v_newsal employees.salary%TYPE;
BEGIN
-- Valid parameter --
SELECT salary
INTO v_oldsal
FROM employees
WHERE employee_id = p_empid;
IF
v_oldsal IS NOT NULL THEN
UPDATE employees
SET salary = salary + 100
WHERE employee_id = p_empid
RETURNING salary
INTO v_newsal;
RETURN v_newsal;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN (0);
END sal_upd;
-- Procedure to update comm and sal using package functions --
PROCEDURE commsal_upd(
p_empid employees.employee_id%TYPE)
IS
v_newcomm employees.commission_pct%TYPE;
v_newsal employees.salary%TYPE;
BEGIN
-- Call package functions to update sal and comm of all employees --
DBMS_OUTPUT.PUT_LINE(comm_upd(p_empid));
DBMS_OUTPUT.PUT_LINE(sal_upd(p_empid));
-- Query for final inform --
SELECT commission_pct, salary
INTO v_newcomm, v_newsal
FROM employees
WHERE employee_id = p_empid;
DBMS_OUTPUT.PUT_LINE('THE NEW COMMISSION FOR EMPLOYEE' || p_empid ||
' IS ' || v_newcomm || ' AND THE NEW SALARY IS ' || v_newsal);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('NO EXISTE EMPLEADO INGRESADO');
END commsal_upd;
END emp_upd_pkg;
Also, I have a little question: When I do use of a function within a procedure, Can I restringe the "RETURN" sentence of the function with the propuse of only send to call Procedure information?
SET SERVEROUTPUT ON
DECLARE
CURSOR cur_empid IS
SELECT employee_id
FROM employees;
TYPE empid_rec IS RECORD(
p_empid employees.employee_id%TYPE);
empid empid_rec;
BEGIN
FOR empid IN cur_empid LOOP
emp_upd_pkg.commsal_upd(empid.employee_id);
EXIT WHEN cur_empid%NOTFOUND;
END LOOP;
END;
/
When I use a simple record to update all employees I receive in console information about RETURN info of functions and info about DBMS... of procedure. Can I change my code to receive only Procedure information on console? Thanks!.
0
24100
THE NEW COMMISSION FOR EMPLOYEE100 IS AND THE NEW SALARY IS 24100
0
17100
THE NEW COMMISSION FOR EMPLOYEE101 IS AND THE NEW SALARY IS 17100
0
17100
THE NEW COMMISSION FOR EMPLOYEE102 IS AND THE NEW SALARY IS 17100
0
9100

Display columns for 4 employee have job id like SA_MAN and have salary >10000

I want to display: employee id, employee name, job id, salary, for 4 employee have job id like SA_MAN and have salary >10000 using loop statements I wrote this code but I get an error
What's wrong with this code?
DECLARE
emp_name employees.last_name%type;
emp_id employees.employee_id%type;
sal employees.salary%type;
jobid employees.job_id%type;
BEGIN
SELECT employee_id,
last_name,
job_id,
salary
INTO emp_id,
emp_name,
jobid,
sal
FROM employees
WHERE salary>10000
AND job_id LIKE'%SA\_%N' ESCAPE'\';
FOR i 1..3 dpms_output.put_line(emp_id||' '||emp_name||' '||jobid||' '||sal);
END LOOP;
END;
This is the error I get:
Error starting at line 1 in command:
DECLARE
emp_name employees.last_name%type;
emp_id employees.employee_id%type;
sal employees.salary%type;
jobid employees.job_id%type;
BEGIN
SELECT employee_id,
last_name,
job_id,
salary
INTO emp_id,
emp_name,
jobid,
sal
FROM employees
WHERE salary>10000
AND job_id LIKE'%SA\_%N' ESCAPE'\';
FOR i 1..3 dpms_output.put_line(emp_id||' '||emp_name||' '||jobid||' '||sal);
END LOOP;
END;
Error report:
ORA-06550: line 20, column 7:
PLS-00103: Encountered the symbol "1" when expecting one of the following:
in
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
This can be achieved by doing the following:
begin
for i in ( SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary > 10000
AND job_id LIKE '%SA\_%N' ESCAPE '\' ) LOOP
dbms_output.put_line( i.employee_id || ' '
|| i.last_name || ' '
|| i.job_id || ' '
|| i.salary );
end loop;
end;
You don't need to do this though. You can just SELECT what you want. More generally, please pay attention to your spacing, it makes your code a lot more readable.
The actual errors are as follows:
If you're performing a FOR LOOP you need an IN and a LOOP
FOR i 1..3 should be for i in 1 .. 3 loop
dbms_output is spelt as I have done, not dpms_output.
You're selecting multiple rows into a type defined as a single row. This will raise the TOO_MANY_ROWS exception. Equally, if this query returned 0 rows a NO_DATA_FOUND exception will be raised.
If you want to select everything and then loop through the values you could use a BULK COLLECT. It's overkill though for this situation. Note that I don't assume the number of values that the query is going to return.
declare
cursor c_emp is
select employee_id, last_name, job_id, salary
from employees
where salary > 10000
and job_id like '%SA\_%N' ESCAPE '\';
type t__emp is table of c_emp%rowtype index by binary_integer;
t_emp t__emp;
begin
open c_emp;
fetch c_emp bulk collect into t_emp;
close c_emp;
for i in t_emp.first .. t_emp.last loop
dbms_output.put_line( i.employee_id || ' '
|| i.last_name || ' '
|| i.job_id || ' '
|| i.salary );
end loop;
end;
/
Apologies for the syntax highlighting. There's a bug with Google Prettify on escaped single quotes in the SQL markdown.

Resources