Table is mutating - oracle

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...

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.

ORA-01007: variable not in select list-1007

I have the table below:
CREATE TABLE req1_tb(TableName VARCHAR2(43),
ColumnName VARCHAR2(98),
Edit_ind CHAR)
Here's the dml for this table:
insert into req1_tb VALUES('Employees','employee_id','Y');
insert into req1_tb VALUES('Employees','first_name','Y');
insert into req1_tb VALUES('Employees','last_name','N');
insert into req1_tb VALUES('Employees','email','N');
insert into req1_tb VALUES('Employees','job_id','N');
insert into req1_tb VALUES('Employees','salary','Y');
insert into req1_tb VALUES('Employees','commission_pct','Y');
insert into req1_tb VALUES('Employees','hire_date','N');
insert into req1_tb VALUES('Employees','department_id','Y');
I assumed that edit_ind column in enter code here below table will change dynamically
SQL> SELECT * FROM REQ1_TB;
TABLENAME COLUMNNAME EDIT_IND
------------------------------------------- --------------- ----------
Employees employee_id Y
Employees first_name Y
Employees last_name N
Employees email N
Employees job_id N
Employees salary Y
Employees commission_pct Y
Employees hire_date N
Employees department_id Y
I have created procedure that will dynamically print columns who are marked 'Y' only:
CREATE OR REPLACE PROCEDURE dyn_sql_sp
AS
cols VARCHAR2(2000);
v_cols VARCHAR2(2000);
cls VARCHAR2(2000);
v_employee_id number;
emp employees%rowtype;
cnt number;
cursor tab_c
is
select columnname from req1_tb
where EDIT_IND='Y';
cursor col_c
is
select employee_id from employees;
BEGIN
for i in tab_C
loop
cols:=cols||'emp.'||i.columnname||',';
end loop;
cols:=rtrim(cols,',');
for i in col_c
loop
EXECUTE IMMEDIATE 'SELECT ' || cols || ' FROM employees WHERE employee_id = :1'
INTO emp
USING i.employee_id;
end loop;
dbms_output.put_line(cols);
Exception
When Others Then
dbms_output.put_line(sqlerrm||sqlcode);
end;
/
While executing I got the following error:
SQL> exec dyn_sql_sp;
ORA-01007: variable not in select list-1007
In your procedure the below code is going to create problem. As far i understand you are trying to select columns of table employee depending on 'Y' flag from table req1_tb.
Problematic Part:
for i in col_c
loop
EXECUTE IMMEDIATE 'SELECT ' || cols || ' FROM employees WHERE employee_id = :1'
--***The INTO clause is problematic here. Since the you select list is not*** having all the columns same as your cursor variable.
INTO emp
USING i.employee_id;
end loop;
Now, you are not trying the same logic while declaring a variable to hold the data returned from those selected columns in Execute Immediate statement.
For that the variable declaration should also be dynamic. So you declaration
emp employees%rowtype;
should be such that it also have all the selected columns satisfying condition flag 'Y'. You cannot insert few columns selected from your select statement to a cursor variable having all the columns.

PL/SQL inserting a new record exception handling

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;
/

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.

Resources