What considerations Do You have about my PLSQL package? - oracle

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

Related

Why in my Procedure is not printing the correct value updated?

Here my code for test:
PROCEDURE INCREASE(p_employee in number)
is
V_salary employees.salary%type;
BEGIN
Select salary into v_salary
From employees where employee_id = p_employee;
if v_salary >= 15000 then
Update employees set salary = v_salary + ((v_salary * 20)/100) Where employee_id = p_employee;
else
Update employees set salary = v_salary + ((v_salary * 10)/100) Where employee_id = p_employee;
end if;
commit;
DBMS_OUTPUT.PUT_LINE('Name: ' || v_name || ' ' || 'salary: ' || v_salary );
End;
When I run the procedure and printed to see the output, we see the result before the update:
enter image description here
When I see the salary for this user is already updated when I select the table Employees:
enter image description here
Because you are not printing the updated value, you are printing the selected value. Your update changes the value of salary in the database, it does NOT change variable selected into. You need to return clause of the update statement. Moreover you don't need to select; this can be done in a single statement, except for setting up to variable and actually printing.
create or replace procedure increase(p_employee in number)
is
v_salary employees.salary%type;
begin
update employees
set salary = case when salary >= 15000
then 1.2 * salary
else 1.1 * salary
end
where employee_id = p_employee
return salary into v_salary;
commit;
dbms_output.put_line('mesalao: ' || v_salary );
end;

Getting pl/sql statement ignored error when writing a procedure

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

PL/SQL INSERT Ignored statement

What I have to do is to INSERT in table "info" different content, depending on the select result: if it is one row, no rows or more than one row.
I want to set the outretvalue variable on the exception section, then do the insert in the IF section, depending on outretvalue value.
Anyway, I get an error at compiling saying that f2 function is in an invalid state. I have 2 errors: for the INSERT and for not recognising rowcount. Why?
CREATE OR REPLACE FUNCTION f2 (v_nume employees.last_name%TYPE DEFAULT 'Bell')
RETURN NUMBER
IS
salariu employees.salary%type;
outretvalue number(2) := 0;
BEGIN
SELECT salary
INTO salariu
FROM employees
WHERE last_name = v_nume;
RETURN salariu;
EXCEPTION
WHEN NO_DATA_FOUND THEN
outretvalue := 1;
WHEN TOO_MANY_ROWS THEN
--at this row I have 2 errors: for the INSERT and for not recognising rowcount
INSERT INTO info(`no_lines`) VALUES(SQL%ROWCOUNT);
END f2;
/
SELECT f2('King') FROM dual;
Your function:
DECLARE
BEGIN
END;
... something
END;
Add another BEGIN at begin or move your IF inside existing BEGIN END block and remove second END.
EDIT: after clarification
CREATE OR REPLACE FUNCTION f2 (v_nume employees.last_name%TYPE DEFAULT 'Bell')
RETURN NUMBER
IS
salariu employees.salary%type;
outretvalue number(2) := 0;
BEGIN
SELECT salary
INTO salariu
FROM employees
WHERE last_name = v_nume;
RETURN salariu;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN -1;
WHEN TOO_MANY_ROWS THEN
SELECT count(*)
INTO salariu
FROM employees
WHERE last_name = v_nume;
INSERT INTO info(no_lines) VALUES(salariu);
RETURN -2;
WHEN OTHERS THEN
RETURN -3;
END f2;
/
SET SERVEROUTPUT on
DECLARE
l_ret NUMBER;
BEGIN
dbms_output.put_line(f2('Bell'));
dbms_output.put_line(f2('noBell'));
dbms_output.put_line(f2('King'));
END;
Try this. It will definelty help you out.
CREATE OR REPLACE FUNCTION f2(
v_nume employees.last_name%TYPE DEFAULT 'Bell')
RETURN NUMBER
IS
salariu employees.salary%type;
outretvalue NUMBER(2) := 0;
lv_cnt PLS_INTEGER;
BEGIN
SELECT salary INTO salariu FROM employees WHERE last_name = v_nume;
RETURN salariu;
EXCEPTION
WHEN NO_DATA_FOUND THEN
outretvalue := 1;
WHEN TOO_MANY_ROWS THEN
SELECT COUNT(1) INTO lv_cnt FROM employees WHERE last_name = v_nume;
INSERT INTO info
( no_lines
) VALUES
( lv_cnt
);
RETURN 2;
WHEN OTHERS THEN
RETURN 3;
END f2;
Oracle saves the compile errors in a table. I use the following query for retrieving the PL/SQL errors in my stored procs/funcs:
SELECT '*** ERROR in ' || TYPE || ' "' || NAME || '", line ' || LINE || ', position ' || POSITION || ': ' || TEXT
FROM SYS.USER_ERRORS
You could try running it and see if it helps identify the error in the function.

cannot reference to cursor instances oracle pl/sql

CREATE OR REPLACE PROCEDURE employee_info_all_in_one
(p_id IN NUMBER)
IS
CURSOR c_city IS
(SELECT l.city
FROM employees e
INNER JOIN departments d
ON (e.department_id = d.department_id)
INNER JOIN locations l
ON (l.location_id = d.location_id)
WHERE e.employee_id = p_id);
CURSOR c_manager IS
(SELECT e1.last_name
FROM employees e1
INNER JOIN
employees e2
ON (e1.employee_id = e2.manager_id)
WHERE e2.employee_id = p_id);
CURSOR c_department_name IS
(SELECT department_name
FROM employees e
INNER JOIN
departments d
ON (e.department_id = d.department_id)
WHERE e.employee_id = p_id);
TYPE EmpRecTyp IS RECORD
( v_annual_sal NUMBER(9,2),
v_monthly_sal NUMBER(9,2),
v_last_name VARCHAR2(10),
v_deptno NUMBER(3),
v_length NUMBER(2),
v_tenure NUMBER(5),
v_job_id VARCHAR2(20),
v_hire_date DATE,
v_city VARCHAR(25),
v_commission_pct NUMBER(2,2),
v_phone_number VARCHAR2(20),
v_manager VARCHAR2(20),
v_comm_calc NUMBER(10,2),
v_email VARCHAR2(10),
v_department VARCHAR2(20),
v_count NUMBER(4)
);
TYPE EmpRecTyp IS REF CURSOR;
emp_c_v EmpRecTyp;
BEGIN
DBMS_OUTPUT.PUT_LINE('Welcome to the summary of an employee based on his unique id');
DBMS_OUTPUT.PUT_LINE('============================================================');
SELECT salary, last_name, department_id,
TRUNC(MONTHS_BETWEEN(SYSDATE,hire_date),0), job_id,
hire_date, commission_pct, phone_number, email
INTO emp_c_v.v_monthly_sal, emp_c_v.v_last_name, emp_c_v.v_deptno,
emp_c_v.v_tenure, emp_c_v.v_job_id, emp_c_v.v_hire_date, emp_c_v.v_commission_pct,
emp_c_v.v_phone_number, emp_c_v.v_email
FROM employees
WHERE employee_id = p_id;
emp_c_v.v_count := SQL%ROWCOUNT;
DBMS_OUTPUT.PUT_LINE(emp_c_v.v_count||' row retrieved...');
DBMS_OUTPUT.PUT_LINE('=============================');
emp_c_v.v_annual_sal := emp_c_v.v_monthly_sal * 12;
emp_c_v.v_length := LENGTH(emp_c_v.v_last_name);
DBMS_OUTPUT.PUT_LINE('Employee:-> ' || emp_c_v.v_last_name || ' ,and his name contains: ' || emp_c_v.v_length ||' chars');
DBMS_OUTPUT.PUT_LINE('=============================');
DBMS_OUTPUT.PUT_LINE(q'[Belong's to department: ]' || emp_c_v.v_deptno);
DBMS_OUTPUT.PUT_LINE('=============================');
IF (emp_c_v.v_monthly_sal < emp_c_v.v_annual_sal)
THEN
DBMS_OUTPUT.PUT_LINE('Has a annual salary of:-> ' || emp_c_v.v_annual_sal);
ELSE
DBMS_OUTPUT.PUT_LINE('Something wrong in the formula!');
END IF;
IF emp_c_v.v_commission_pct IS NULL
THEN
DBMS_OUTPUT.PUT_LINE('No Commission added to the annual salary!');
ELSE
DBMS_OUTPUT.PUT_LINE('Commission percentage to the salary is:-> '|| emp_c_v.v_commission_pct ||'%');
emp_c_v.v_comm_calc := (emp_c_v.v_annual_sal * emp_c_v.v_commission_pct) + emp_c_v.v_annual_sal;
DBMS_OUTPUT.PUT_LINE('And calculated with annual salary is:->' ||v_comm_calc);
END IF;
DBMS_OUTPUT.PUT_LINE('Working for:-> '|| emp_c_v.v_tenure || ' months as '|| emp_c_v.v_job_id);
DBMS_OUTPUT.PUT_LINE('=============================');
DBMS_OUTPUT.PUT_LINE('Started in:-> '|| emp_c_v.v_hire_date);
DBMS_OUTPUT.PUT_LINE('=============================');
DBMS_OUTPUT.PUT_LINE('Phone number:-> '||emp_c_v.v_phone_number);
DBMS_OUTPUT.PUT_LINE('=============================');
DBMS_OUTPUT.PUT_LINE('Email:-> '||emp_c_v.v_email);
DBMS_OUTPUT.PUT_LINE('=============================');
OPEN c_city;
FETCH c_city INTO v_city;
IF c_city%FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Location:-> '||emp_c_v.v_city);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee location unknown');
END IF;
CLOSE c_city;
OPEN c_manager;
FETCH c_manager INTO emp_c_v.v_manager;
IF c_manager%FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Is in the eyes of manager:-> '||emp_c_v.v_manager);
ELSE
DBMS_OUTPUT.PUT_LINE('Slave '||emp_c_v.v_last_name||' is free!');
END IF;
CLOSE c_manager;
OPEN c_department_name;
FETCH c_department_name INTO emp_c_v.v_department;
IF c_department_name%FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Department Name:-> '||emp_c_v.v_department);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee ' ||emp_c_v.v_last_name||' belongs to no department!');
END IF;
DBMS_OUTPUT.PUT_LINE('================================');
DBMS_OUTPUT.PUT_LINE('Checking for employee with id '|| p_id ||'..');
IF (check_sal2(p_id) IS NULL)
THEN
DBMS_OUTPUT.PUT_LINE('The function returned NULL due to exception, therefore employee does not exist!');
ELSIF (check_sal2(p_id))
THEN
DBMS_OUTPUT.PUT_LINE('Employees salary > average of department '||emp_c_v.v_deptno||' where he belongs.');
ELSE
DBMS_OUTPUT.PUT_LINE('Salary < average of department '||emp_c_v.v_deptno||', where he belongs.');
END IF;
DBMS_OUTPUT.PUT_LINE('=====================================================');
END;
Initially i had only simple variables (v_...) declared in this sub-program but i wanted to make use of true cursor variables i.e like-pointers? i suppose. So i modified and defined a type of record and referenced a cursor "...IS REF CURSOR" for the variables or fields inside it. But when i compile this whole thing i get the error of invalid reference to variable "emp_c_v", why? I am still in the learning stages so sorry for talking nonsense. Thanks
A cursor is a pointer to a result set (sort of), not to an individual record. You can't ever modify a result set. In this case the pointer wouldn't actually point to anything as there isn't a result set (from a query) for it to point to.
Your code will almost compile if you drop the ref cursor and make your variable a record type; so instead of:
TYPE EmpCurTyp IS REF CURSOR;
emp_c_v EmpCurTyp;
use:
emp_c_v EmpRecTyp;
You've also missed a couple of places when changing your references:
DBMS_OUTPUT.PUT_LINE('And calculated with annual salary is:->' ||v_comm_calc);
and
FETCH c_city INTO v_city;
... both need the emp_c_v. prefix before v_comm_calc and v_city respectively.
I assume you're using this as a learning exercise, otherwise this could all be done much more simply.

Function Returning Multiple Values SQL

I have been trying to return 2 values from a function in PL/SQL . The first value i want it to be the salary of the guy i have to search for. The second i want it to be the number of rows affected by this. I searched google for a while and i found out that i must first make a type so that i can return the data. However i get an error :
Error(9,1): PL/SQL: SQL Statement ignored
Error(9,36): PL/SQL: ORA-00936: missing expression
The code that i have is :
CREATE OR REPLACE TYPE return_type AS OBJECT(val1 NUMBER,val2 NUMBER);
CREATE OR REPLACE FUNCTION f2
(v_nume employees.last_name%TYPE DEFAULT 'Bell')
RETURN return_type IS
out_var return_type;
salariu employees.salary%type;
BEGIN
SELECT salary INTO salariu
FROM employees
WHERE last_name = v_nume;
INSERT INTO out_var values(salariu,##ROWCOUNT);
RETURN out_var;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000, 'Nu exista angajati cu numele dat');
WHEN TOO_MANY_ROWS THEN
RAISE_APPLICATION_ERROR(-20001, 'Exista mai multi angajati cu numele dat');
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20002,'Alta eroare!');
END f2;
/
I did it this way:
CREATE OR REPLACE FUNCTION f2
(v_nume employees.last_name%TYPE DEFAULT 'Bell',
nr OUT employees.salary%TYPE )
RETURN NUMBER IS
salariu employees.salary%type;
BEGIN
SELECT salary INTO salariu
FROM employees
WHERE last_name = v_nume;
nr := SQL%ROWCOUNT;
RETURN salariu;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000,
'Nu exista angajati cu numele dat');
WHEN TOO_MANY_ROWS THEN
RAISE_APPLICATION_ERROR(-20001,
'Exista mai multi angajati cu numele dat');
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20002,'Alta eroare!');
END f2;
/

Resources