associative arrays and loops - sql

I need to select employees with employee_id from 100 to 110, loop through emp table and add 10% to each emp_salary, then display results from the emp table
DECLARE
vname VARCHAR(100);
TYPE emp_table_type is TABLE OF employees.last_name%TYPE
INDEX BY PLS_INTEGER;
vname_table emp_table_type;
BEGIN
for i in 100..110
SELECT last_name into vname from employees where employee_id = i;
end loop;
vname_table(1) := vname;
DBMS_OUTPUT.PUT_LINE(vname_table(1));
End;

I need to select employees with employee_id from 100 to 110, loop
through emp table and add 10% to each emp_salary, then display results
from the emp table
You can do it as :
DECLARE
sal NUMBER;
TYPE emp_table_type IS TABLE OF employee.employee_id%TYPE
INDEX BY PLS_INTEGER;
vname_table emp_table_type;
BEGIN
---Selecting employee
SELECT employee_id
BULK COLLECT INTO vname_table
FROM employee
WHERE employee_id BETWEEN 100 AND 110;
FOR i IN 1 .. vname_table.LAST
LOOP
--- Updating Salary
UPDATE Employee
SET salary = salary + (salary * 0.10)
WHERE employee_id = vname_table (i)
RETURNING salary
INTO sal;
--- Displaying updated salary
DBMS_OUTPUT.PUT_LINE (sal);
END LOOP;
END;

Related

REPLACE procedure on oracle 12c

When selecting the employee name and salary of 1500 if there is 1 employee, insert into tMessage the employee's name and the salary amount. If there are 2 or more employees, insert multiple lines. If there are no employees then insert into tMessage without any staff.
create or REPLACE procedure temployees_i(
v_aempname in tregions.aregid%type,
v_aempsal number(3):=1500),
)
is
BEGIN
select lastname,salary from employees ;
EXCEPTION
WHEN SALARY=v_aempsal THEN
insert into tMessage values ('have qualified staff'|| lastname ||'of' salary);
WHEN SALARY!=v_aempsal THEN
insert into tMessage values ('There are no employees
');
END;
I think that's you want.
CREATE OR REPLACE PROCEDURE temployees_i( v_aempsal number := 1500 )
IS
TYPE emprec IS RECORD (empname VARCHAR2(50), salary NUMBER(9,2));
TYPE emp_tab IS TABLE OF emprec;
empv emp_tab;
BEGIN
SELECT lastname, salary bulk COLLECT INTO empv from employees WHERE
SALARY = v_aempsal ;
IF empv.count != 0 then
FORALL i in 1..empv.COUNT
insert into tMessage values ('have qualified staff '||
empv(i).empname ||'of ' ||empv(i).salary);
ELSE
INSERT INTO tMessage VALUES ('There are no employee');
END IF;
COMMIT;
END;

Why am I getting error in trigger when I update salary of employee?

create or replace TRIGGER CHECK_GRADE
BEFORE INSERT OR UPDATE ON EMPLOYEE
FOR EACH ROW
DECLARE
LoSal NUMBER(8, 2);
HiSal NUMBER(8, 2);
Letter VARCHAR(1);
Sal NUMBER(8, 2);
BEGIN
IF(:NEW.GLetter IS NOT NULL)
THEN
Sal := NVL(:NEW.Salary, -1);
SELECT MinSalary, MaxSalary
INTO LoSal, HiSal
FROM GRADE
WHERE GLetter = :NEW.GLetter;
IF(NOT(Sal BETWEEN LoSal AND HiSal))
THEN
RAISE_APPLICATION_ERROR(-20001, 'Salary does not correspond to grade error! ' );
END IF;
ELSIF(:NEW.Salary IS NOT NULL)
THEN
SELECT GLetter
INTO Letter
FROM GRADE
WHERE :NEW.Salary BETWEEN MinSalary AND MaxSalary;
:NEW.GLetter := Letter;
END IF;
END;
This is the sql statement I run
basically what I want to do is that when a user tries to update the salary of an employee the trigger will automatically fill the grade of the employee which corresponds to his/her salary
update employee set salary = 25500 where employeeid = 1006;
Table for employee
has attributes like name department name and others and salary and grade
Table for Grade has
minsalary
max salary
gradeletter
Error starting at line : 2 in command -
update employee set salary = 25500 where employeeid = 1006
Error report -
ORA-20001: Salary does not correspond to grade error!
ORA-06512: at "gh12345.CHECK_GRADE", line 18
ORA-04088: error during execution of trigger 'gh12345.CHECK_GRADE'
The error is being raised because of this part here:
SELECT MinSalary, MaxSalary
INTO LoSal, HiSal
FROM GRADE
WHERE GLetter = :NEW.GLetter;
IF(NOT(Sal BETWEEN LoSal AND HiSal))
THEN
RAISE_APPLICATION_ERROR(-20001, 'Salary does not correspond to grade error! ' );
END IF;
you are setting the salary to the value 25500 which is out of the range defined in this table GRADE.
So you should do a query on this table and define a value for Salary that is within this range, or update the GRADE table for your new disired range.

Table not updating when trigger is fired

I have 2 tables:
Employees(Employee_ID, First_name, Last_name, Email, Hire_date, Department_ID)
Departments(Department_ID, Department_name, Total_employees).
I have created trigger that fires after inserting an employee to employees table. It increases the total_employees column by 1 for :new inserted Department_ID.
Trigger:
create or replace TRIGGER emp_count_department
AFTER INSERT OR DELETE ON EMPLOYEES
for each row
DECLARE
counter NUMBER;
BEGIN
if inserting then
select total_employees into counter
from departments
where department_id = :new.department_id;
update departments
set total_employees = counter+1
where department_id = :new.department_id;
elsif deleting then
select total_employees into counter
from departments
where department_id = :old.department_id;
update departments
set total_employees = counter-1
where department_id = :old.department_id;
end if;
END;
When I try to insert an employee, it is inserted but it doesn't increase total_employees by 1 in departments table. When I try to insert an employee with a department_ID that doesn't exist in departments table, it gives me error. So the trigger is working but not increasing the total numbers by 1.
Try this:
create or replace TRIGGER emp_count_department
AFTER INSERT OR DELETE ON EMPLOYEES
for each row
BEGIN
if inserting then
update departments
set total_employees = total_employees+1
where department_id = :new.department_id;
elsif deleting then
update departments
set total_employees = total_employees-1
where department_id = :old.department_id;
end if;
END;
I did simple testing of your code in Oracle 11g and it seems to work.
Please check if you missed in adding information.
create table emp1(emp_id number ,dept_id number);
create table dept1 (dept_id number ,total_emp number);
CREATE OR replace TRIGGER emp_count_dept
AFTER INSERT OR DELETE ON emp1
FOR EACH ROW
DECLARE
counter NUMBER;
BEGIN
IF inserting THEN
UPDATE dept1
SET total_emp = total_emp + 1
WHERE dept_id = :new.dept_id;
ELSIF deleting THEN
UPDATE dept1
SET total_emp = total_emp - 1
WHERE dept_id = :old.dept_id;
END IF;
END;
insert into dept1 values(10,10);
insert into emp1 values(10,10);
select * from dept1;
DEPT_ID TOTAL_EMP
10 11
I think you are missing an important use case, what if the employees table is updated and the dept_id changes. To expand upon the answer #pmdba gave, I think the following code would work best.
CREATE OR REPLACE TRIGGER emp_count_dept
AFTER INSERT OR UPDATE OF DEPT_ID OR DELETE ON employees
FOR EACH ROW
BEGIN
IF :new.dept_id IS NOT NULL THEN
UPDATE departments d
SET d.total_employees = NVL(d.total_employees, 0)+1
WHERE d.department_id = :new.dept_id;
END IF;
IF :old.dept_id IS NOT NULL THEN
UPDATE departments d
SET d.total_employees = d.total_employees - 1
WHERE d.department_id = :old.dept_id;
END IF;
END;
/
This takes care of UPDATE statements now. And also takes care of the first INSERT for a given department (If you didn't initialize all departments.total_employee to 0 when you created them).
I also created this DBFiddle demonstrating the functionality (And why you need the NVL function or to default your TOTAL_EMPLOYEES column to 0) (Link)

PL/SQL procedure to compare 3 employees' salary, then swap the lowest and highest salary

I'm looking to have a procedure that takes in 3 employee_id's as parameters then compares them, the lowest and highest will be swapped while the middle one is left alone. I'm not sure if I'm approaching this correctly, I keep getting errors on oracle apex in the if else section. I've read maybe implementing a case statement could be easier?
--Note: this is a homework question
What I have so far:
create or replace procedure myproc(empid in number, empid in number, empid in number) is
originalsalary1 employees.salary%type;
originalsalary2 employees.salary%type;
originalsalary3 employees.salary%type;
newsalary employees.salary%type;
begin
select salary INTO originalsalary1 from employees
where employee_id = empid;
select salary INTO originalsalary2 from employees
where employee_id = empid;
select salary INTO originalsalary3 from employees
where employee_id = empid;
if originalsalary1 <= originalsalary2 and originalsalary3 then
newsalary := originalsalary1 * 1.1;
elseif originalsalary2 <= originalsalary1 and originalsalary3 then
newsalary := originalsalary2 * 1.1;
elseif originalsalary3 <= originalsalary1 and originalsalary2 then
newsalary := originalsalary3 * 1.1;
end if;
end;
/
CREATE OR REPLACE PROCEDURE PR_PREP(EMPID1 IN INT, EMPID2 IN INT , EMPID3 IN
INT)
IS
MAX_SAL_EMP_ID INT;
MIN_SAL_EMP_ID INT;
MAX_SAL EMPLOYEES.SALARY%TYPE;
MIN_SAL EMPLOYEES.SALARY%TYPE;
BEGIN
SELECT EMP_ID , SALARY INTO MAX_SAL_EMP_ID , MAX_SAL FROM EMPLOYEES WHERE
EMP_ID IN (EMPID1, EMPID2, EMPID3)
AND SALARY = (SELECT MAX(SALARY) FROM EMPLOYEES WHERE EMP_ID IN (EMPID1,
EMPID2, EMPID3));
SELECT EMP_ID , SALARY INTO MIN_SAL_EMP_ID , MIN_SAL FROM EMPLOYEES WHERE
EMP_ID IN (EMPID1, EMPID2, EMPID3)
AND SALARY = (SELECT MIN(SALARY) FROM EMPLOYEES WHERE EMP_ID IN (EMPID1,
EMPID2, EMPID3));
UPDATE EMPLOYEES SET SALARY = MAX_SAL WHERE EMP_ID = MIN_SAL_EMP_ID;
UPDATE EMPLOYEES SET SALARY = MIN_SAL WHERE EMP_ID = MAX_SAL_EMP_ID;
COMMIT;
END;

SQL Using an OBJECT as parameter for an ORDER mthod

I have a TYPE called Employee which has an ORDER method which takes an Employee as a parameter. I have created a table of Employee and inserted some data. I am trying to test this ORDER method using SELECT however i am having difficulty satisfying the parameter. here is my code
CREATE OR REPLACE TYPE Employee AS OBJECT(
EmpID VARCHAR(15),
eName VARCHAR(30),
ePhone NUMBER,
eAddress VARCHAR(15),
ePosition VARCHAR(15),
eHireDt DATE,
salary NUMBER,
ORDER MEMBER FUNCTION orderSalary (e Employee) RETURN NUMBER)
NOT FINAL;
/
CREATE OR REPLACE TYPE BODY Employee AS
ORDER MEMBER FUNCTION orderSalary(e Employee) return number IS
BEGIN
IF(self.salary > e.salary) then
return(1);
ELSIF (self.salary < e.salary) then
return(-1);
ELSE
return(0);
END IF;
END;
END;
/
CREATE TABLE Emp OF Employee (EmpID PRIMARY KEY)
OBJECT IDENTIFIER PRIMARY KEY;
insert into Emp values('001','kabir',6477732272,'Pharmacy','clerk','2016-03-28',2000);
Here is the line that is giving me trouble:
SELECT p.orderSalary(Employee s) FROM Emp p;
All i need to do is test this method to make sure it works, is there any way i can create an instance of Employee to use as a parameter, or perhaps take a row from the Emp table? Thanks!
SELECT p.orderSalary( VALUE( p ) ) FROM Emp p;
Or:
SELECT p.orderSalary( DEREF( REF( p ) ) ) FROM Emp p;
Or:
SET SERVEROUTPUT ON;
DECLARE
e1 EMPLOYEE := NEW EMPLOYEE('001','kabir',6477732272,'Pharmacy','clerk',DATE '2016-03-28',2000);
e2 EMPLOYEE := NEW EMPLOYEE('002','bob',1234567890,'Library','assistant',DATE '2016-03-07',1000);
BEGIN
DBMS_OUTPUT.PUT_LINE( e1.orderSalary( e2 ) );
END;
/
Update - Select different rows:
insert into Emp values('001','kabir',6477732272,'Pharmacy','clerk','2016-03-28',2000);
insert into Emp values('002','bob',1234567890,'Library','assistant',DATE '2016-03-07',1000);
SELECT e1.ename AS name1,
e2.ename AS name2,
e1.orderSalary( VALUE( e2 ) )
FROM Emp e1
CROSS JOIN Emp e2;
Outputs:
NAME1 NAME2 E1.ORDERSALARY(VALUE(E2))
------ ------ -------------------------
kabir kabir 0
kabir bob 1
bob kabir -1
bob bob 0