PL/SQL inserting a new record exception handling - oracle

I have an assignment in Oracle PL/SQL. I have to count the maximum number of employees working under a manager, and if this manager has more than 7 employees working under him I must raise an exception, which gives the message:
('Manager ||manager_name||' has maximium number of employees working under him'.)
Otherwise I must insert a new employee and give the message:
('It was inserted a new employee for the manager ||manager_name).
I have written the code, but I know something is wrong.
create table temp_emp as select * from employees;
select * from temp_emp;
create or replace procedure insert_emp(mngrId IN temp_emp.manager_id%type)
IS
ex_hugemp EXCEPTION;
emp_counter NUMBER;
fname temp_emp.first_name%type;
BEGIN
SELECT COUNT(*) INTO emp_counter
FROM temp_emp
WHERE temp_emp.manager_id=mngrId;
IF emp_counter > 7 THEN
RAISE ex_hugemp;
ELSE
INSERT INTO temp_emp(EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER
,HIRE_DATE, JOB_ID, SALARY, COMMISSION_PCT
,MANAGER_ID,DEPARTMENT_ID)
VALUES(LENGTH(EMPLOYEE_ID)+1, 'KAY', 'HORSTMAN', NULL, NULL
,'28-MAY-2013', 'IT_PROG', 24000, NULL, 103, 60);
DBMS_OUTPUT.PUT_LINE('It was inserted a new employee for the manager '||fname);
END IF;
EXCEPTION
WHEN ex_hugemp THEN
DBMS_OUTPUT.PUT_LINE('Manager '||fname||' has maximium number of employees working under him.');
END;
/

Your variable fname is empty. Fill it:
SELECT first_name
INTO fname
FROM temp_emp
WHERE employee_id = mngrid;
Use for the insert the same mngrid. Why is 103?
What is
LENGTH(EMPLOYEE_ID)+1
First: this will convert employee_id in string, get the length from the string and add 1. Do you really want this?. And second: you cannot use column name in values(). Create sequence (change 1 with your value to start):
CREATE SEQUENCE TEMP_EMP_SEQ START WITH 1;
and than use it in your procedure
temp_emp_seq.nextval
.
CREATE OR REPLACE PROCEDURE insert_emp (mngrid IN temp_emp.manager_id%TYPE) IS
ex_hugemp EXCEPTION;
emp_counter NUMBER;
fname temp_emp.first_name%TYPE;
BEGIN
SELECT first_name
INTO fname
FROM temp_emp
WHERE employee_id = mngrid;
SELECT COUNT (*)
INTO emp_counter
FROM temp_emp
WHERE temp_emp.manager_id = mngrid;
IF emp_counter > 7 THEN
RAISE ex_hugemp;
ELSE
INSERT INTO temp_emp (employee_id, first_name, last_name, email, phone_number, hire_date, job_id, SALARY,COMMISSION_PCT,MANAGER_ID,DEPARTMENT_ID)
VALUES( temp_emp_seq.nextval,'KAY','HORSTMAN',NULL,NULL,TO_DATE('28-05-2013','dd-mm-yyyy'),'IT_PROG',24000,NULL,mngrid,10);
DBMS_OUTPUT.put_line ('It was inserted a new employee for the manager ' || fname);
END IF;
EXCEPTION
WHEN ex_hugemp THEN
DBMS_OUTPUT.put_line ('Manager ' || fname || ' has maximium number of employees working under him.');
END;
/

Related

Procedure to delete employee records from employee table

Create a procedure that deletes employee records from the Employee table. Get the department name as an input parameter. Delete the employee records who belongs to that department.
Display the count of employee records that were deleted. If the respective department was not found, then raise "DeptNotFoundException" and print the message 'No Records found.'
Assume the Employee table has been already created and a few records have been inserted.
EMPLOYEE:
Column name Data type Constraints
EMP_ID NUMBER(5) PK
EMP_NAME VARCHAR2(25) NOT NULL
SALARY NUMBER(10,2)
DEPT VARCHAR2(25)
EMP_ID EMP_NAME SALARY DEPT
------ -------- ------- -----
101 Tom 54000 MECH
102 William 43000 CSE
103 John 34560 MECH
104 Smith 56000 CSE
105 Steve 23450 IT
Functional Requirements:
PROCEDURE DELETE_EMPLOYEE( v_dept IN EMPLOYEE.dept%TYPE)
Sample Output:
2 Employee record(s) got deleted.
(Hint: Data is case sensitive. Use '/' to terminate the PLSQL block)
I have tried to solve this using my own logic, but it is showing error(out of 2 test only one is passed) can anyone point out the mistake?
set serveroutput on;
create or replace PROCEDURE DELETE_EMPLOYEE(v_dept IN EMPLOYEE.dept%TYPE)
is
temp number;
DEPTNOTFOUNDEXCEPTION Exception;
begin
select count(dept) into temp from EMPLOYEE where dept=v_dept;
delete from EMPLOYEE where dept=v_dept;
if temp>=1 then
dbms_output.put_line(temp||' Employee record(s) got deleted.');
else
raise DEPTNOTFOUNDEXCEPTION;
end if;
exception
when DEPTNOTFOUNDEXCEPTION then
dbms_output.put_line('No Records Found.');
end;
/
As others have pointed out, you can use SQL%ROWCOUNT and generally tidy up a bit but it doesn't look "wrong".
CREATE TABLE employee (
emp_id NUMBER(5) PRIMARY KEY
, emp_name VARCHAR2(25) NOT NULL
, salary NUMBER(10,2)
, dept VARCHAR2(25)
);
INSERT INTO employee (emp_id, emp_name, salary, dept) VALUES (101, 'Tom', 54000, 'MECH');
INSERT INTO employee (emp_id, emp_name, salary, dept) VALUES (102, 'William', 43000, 'CSE');
INSERT INTO employee (emp_id, emp_name, salary, dept) VALUES (103, 'John', 34560, 'MECH');
INSERT INTO employee (emp_id, emp_name, salary, dept) VALUES (104, 'Smith', 56000, 'CSE');
INSERT INTO employee (emp_id, emp_name, salary, dept) VALUES (105, 'Steve', 23450, 'IT');
DECLARE
dept_not_found EXCEPTION;
PROCEDURE delete_employee (p_dept IN employee.dept%TYPE) IS
BEGIN
DELETE employee
WHERE dept = p_dept;
IF SQL%ROWCOUNT = 0 THEN
RAISE dept_not_found;
END IF;
dbms_output.put_line(SQL%ROWCOUNT||' Employee record(s) got deleted.');
END delete_employee;
BEGIN
delete_employee('CSE');
delete_employee('ZZZ');
EXCEPTION
WHEN dept_not_found THEN
dbms_output.put_line('No Records Found.');
END;
/
2 Employee record(s) got deleted.
No Records Found.
PL/SQL procedure successfully completed.
Only an advice: Stop using raise when you want to output something. raise have always much more workload than:
if (sql%rowcount = 0) then
DBMS_Output.Put_Line('No Record Found');
return;
end if;

PL/SQL Loop issue with Cursor

I am trying to create a PL/SQL script that selects the last name and salary of an employee from the table employees. I have a cursor that stores the data and I fetch the cursor which then inserts the data into a new table called BIG_MONEY. I have a user input that selects the number of employees the loop will run through and the loop ends when it reaches the figure they provided.
SET SERVEROUTPUT ON
DROP TABLE BIG_MONEY;
ACCEPT NumberOfStaff
CREATE TABLE BIG_MONEY (
last_name VARCHAR2(10),
salary NUMBER(7, 2)
);
DECLARE V_EMP_ID employees.employee_id%TYPE;
V_EMP_LASTNAME employees.last_name%TYPE;
V_EMP_SALARY employees.salary%TYPE;
CURSOR EMP_Cursor IS
SELECT employee_id, last_name, salary
FROM employees
ORDER BY salary DESC last_name ASC
BEGIN
OPEN EMP_Cursor;
LOOP
FETCH EMP_Cursor INTO V_EMP_ID, V_EMP_LASTNAME, V_EMP_SALARY;
INSERT INTO BIG_MONEY (last_name, salary)
VALUES (V_EMP_LASTNAME, V_EMP_SALARY)
EXIT WHEN EMP_Cursor%ROWCOUNT = '&NumberOfStaff';
DMBS_OUTPUT.PUT_LINE
('Employee' || TO_CHAR (V_EMP_ID) || 'last name is' || TO_CHAR (V_EMP_LASTNAME)
|| 'and makes' || TO_CHAR (V_EMP_SALARY) || 'a month');
END LOOP;
CLOSE EMP_Cursor;
What am I doing wrong here? I would assume my logic is correct but the syntax is where I'm making a mistake.

Table is mutating

after i insert this code, i got an error telling that
ORA-04091: table (schema).EMPLOYEES is mutating, trigger/function may not see it
ORA-06512: at "HR.TRGADDEMP_1215034", line 7
ORA-04088: error during execution of trigger 'HR.TRGADDEMP_1215034'
What should i do?
CREATE OR REPLACE TRIGGER TrgAddEmp_1215034
AFTER INSERT ON Employees
FOR EACH ROW
DECLARE
v_name varchar2(35);
v_managerName varchar2(20);
v_dept varchar2(35);
BEGIN
Select first_name||' '||last_name
INTO v_name
FROM Employees where employee_id = :new.employee_id;
Select last_name
into v_managerName
from employees where employee_id = :new.manager_id;
Select department_name
into v_dept
from departments where department_id = :new.department_id;
IF v_managerName is NULL THEN
DBMS_OUTPUT.PUT_LINE('There is a new employee '|| v_name );
DBMS_OUTPUT.PUT_LINE('The supervisor for this employee has not been decided');
DBMS_OUTPUT.PUT_LINE('This employee is assigned to '||v_dept|| 'Department');
ELSIF v_dept is NULL THEN
DBMS_OUTPUT.PUT_LINE('There is a new employee '|| v_name );
DBMS_OUTPUT.PUT_LINE('This employee is supervised by ' || v_managerName);
DBMS_OUTPUT.PUT_LINE('The department for this employee has not been decided');
ELSE
DBMS_OUTPUT.PUT_LINE('There is a new employee '|| v_name );
DBMS_OUTPUT.PUT_LINE('This employee is supervised by ' || v_managerName);
DBMS_OUTPUT.PUT_LINE('This employee is assigned to '||v_dept|| 'Department');
END IF;
END;
You should insert a correct code instead of this :)
ORA-4091 means that your triggers tried to select data from it's own table. Just don't do it. Never. Row-level triggers will not allow that.
This code tries to select a data which you already have.
Why you're trying to select first_name & last_name when you have :new.first_name and :new.last_name? And so on...

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.

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