PL/SQL invalid ROWID for update - oracle

I try update salary, but get error:
invalid ROWID
Cause: A ROWID was entered incorrectly. ROWIDs must be entered as
formatted hexadecimal strings using only numbers and the characters A
through F. A typical ROWID format is '000001F8.0001.0006'.
this is my code
DECLARE
CURSOR get_sls(mgr NUMBER, dep VARCHAR2) IS
SELECT *
FROM emp_n_m
WHERE emp_n_m.mgr = mgr
FOR UPDATE OF emp_n_m.sal ;
BEGIN
OPEN get_sls(7902, 'SALES');
if (get_sls%notfound) then
dbms_output.put_line('incorrect mgr');
else
UPDATE emp_n_m
SET emp_n_m.sal = emp_n_m.sal + 50
WHERE CURRENT OF get_sls;
COMMIT;
end if;
CLOSE get_sls;
END;
/

this should work:
DECLARE
CURSOR get_sls(mgr NUMBER, dep VARCHAR2) IS
SELECT *
FROM emp_n_m
WHERE emp_n_m.mgr = mgr
FOR UPDATE OF emp_n_m.sal ;
v_emp get_sls%rowtype;
BEGIN
OPEN get_sls(7902, 'SALES');
FETCH get_sls INTO v_emp;
if (get_sls%notfound) then
dbms_output.put_line('incorrect mgr');
else
UPDATE emp_n_m
SET emp_n_m.sal = emp_n_m.sal + 50
WHERE CURRENT OF get_sls;
COMMIT;
end if;
CLOSE get_sls;
END;
/

Is the cursor really required in your case? Would it not be efficient to get this done in a DML operation?
All you want to do is to update salary for manager 7902 from dept 'SALES ...
UPDATE emp_n_m SET emp_n_m.sal = emp_n_m.sal + 50
WHERE emp_n_m.mgr = 7902
AND dept = 'SALES';
COMMIT;

Related

PLSQL Updating employee salary where department_id = 30 using cursor

I need to update employee salary from department 30. all employees from department 30 will have 20% salary increase. I run into error while executing my code.
Here is my code:
DECLARE
CURSOR cur_emp
IS
SELECT * FROM employees WHERE department_id = 30;
rec_emp cur_emp%rowtype;
BEGIN
OPEN cur_emp;
LOOP
FETCH cur_emp INTO rec_emp;
IF rec_emp.department_id = 30 THEN
UPDATE employees
SET salary = salary + (salary * 0.20)
WHERE employee_id = rec_emp.employee_id;
END IF;
EXIT
WHEN cur_emp%notfound;
END LOOP;
CLOSE cur_emp;
END;
/
You can handle the task only by one DML statement rather than a code block, after commenting out the parts of the trigger's code which leads to the current issue or disabling it of course, such as
SQL> UPDATE employees
SET salary = ROUND(salary * 1.2,2)
WHERE department_id = 30;
/
SQL> COMMIT;

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;

PL/ SQL- WHEN / Conditional commands

I am trying to increase the salary of three employees by prompting the user. The job_ids are 1, 4, and 8. I cannot seem to get my WHEN statements to work or properly interact with the datatables. Anyone have any insights?
SET SERVEROUTPUT ON
SET VERIFY OFF
accept selection prompt 'Please enter your employee ID'
DECLARE
JobNumber INT(2) := ('&selection.');
NewSalary VARCHAR2(30);
BEGIN
update emp_employee
set NewSalary = case
WHEN JobNumber = '1' THEN NewSalary := emp_employees.salary * 1.10;
WHEN JobNumber = '4' THEN NewSalary := emp_employees.salary * 1.15;
WHEN JobNumber = '8' THEN NewSalary := emp_employees.salary * 1.20;
ELSE 'Invalid ID'
END;
DBMS_OUTPUT.PUT_LINE ('Job ID '|| JobNumber || 'Salary ' || NewSalary);
END;
/
i think your update should be like below
update emp_employee
set NewSalary = case
WHEN JobNumber = 1 THEN emp_employees.salary * 1.10;
WHEN JobNumber = 4 THEN emp_employees.salary * 1.15;
WHEN JobNumber = 8 THEN emp_employees.salary * 1.20;
ELSE null
END;
//NewSalary is numeric field you can not assign string value invalid
As you didn't provide test case, I'm using Scott's schema and his EMP table. The principle is the same, though.
Have a look a this example and note the differences:
CASE you wrote is wrong; you've already said that NewSalary should be something (within the UPDATE), so you don't repeat it once again)
ELSE can't be 'Invalid ID'; you'd put a string into a NUMBER datatype column. I handled it within the IF statement - if nothing has been updated, such an employee doesn't exist.
you can't output NewSalary as you don't know it. I returned its value into a separate local variable (l_new_sal)
Also, if I were you, I'd rather create a stored procedure instead of using an anonymous PL/SQL block. If you use it for educational purposes, let it be (but you can try to convert it to a procedure, if you want).
Here you go; one example with a non-existent EMPNO, and another one for employee that exists.
SQL> set serveroutput on
SQL> set ver off
SQL> accept par_selection prompt 'Enter EMPNO: '
Enter EMPNO: 1234
SQL> declare
2 l_empno emp.empno%type := &par_selection; -- it is employee ID, not job number!
3 l_new_sal emp.sal%type;
4 l_cnt number;
5 begin
6 update emp e set
7 e.sal = case when e.deptno = 10 then e.sal * 1.1
8 when e.deptno = 20 then e.sal * 1.15
9 when e.deptno = 30 then e.sal * 1.2
10 else e.sal
11 end
12 where e.empno = l_empno
13 returning sal into l_new_sal;
14
15 l_cnt := sql%rowcount;
16
17 if l_cnt > 0 then
18 dbms_output.put_line('Employee ' || l_empno || ', new salary = ' || l_new_sal);
19 else
20 dbms_output.put_line('Nobody got new salary');
21 end if;
22 end;
23 /
Nobody got new salary
PL/SQL procedure successfully completed.
SQL> accept par_selection prompt 'Enter EMPNO: '
Enter EMPNO: 7369
SQL> /
Employee 7369, new salary = 920
PL/SQL procedure successfully completed.
SQL>

How to handle exception in cursor when given record is not found in a table

I am updating emp3 (same as emp table) using a Cursor For loop,
DECLARE
CURSOR incr_cur IS SELECT * FROM emp3 FOR UPDATE OF sal;
v_job emp3.job%TYPE := '&ENTER_Job';
v_cnt INTEGER := 0;
BEGIN
FOR r_l IN incr_cur LOOP
IF v_job IN (r_l.job) THEN
UPDATE emp3 SET sal = sal + 100 WHERE CURRENT OF incr_cur;
END IF;
END LOOP;
FOR r_l IN incr_cur LOOP
IF v_job IN (r_l.job) THEN
v_cnt := v_cnt + 1;
DBMS_OUTPUT.PUT_LINE('The Salary of ' || r_l.ename || ' is Incremented by 100 and the Updated Salary is: $' || r_l.sal);
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('The Salary of '|| v_cnt ||' Employees are Updated');
END;
When executing the PL/SQL block it will ask for the job,
I give MANAGER, then the salary of the employees who are MANAGER is incremented by 100.
The emp3 table has 5 JOB categories CLERK, MANAGER, ANALYST, SALESMAN and PRESIDENT.
Then how to display the Message The Job is not listed so update is not possible., if a user inputs a JOB which is not in the table such as DEVELOPER.
I had tried with exception handling but could not get it to work.
There is no need for a separate step. Just attempt the update and if no rows were updated, say so. If you want it to be an exception, then raise one with raise_application_error.
Assuming this is a learning exercise and this is why you don't want to just do an ordinary update, you might do something like this:
declare
k_job constant emp3.job%type := '&JOB';
cursor employees_cur is
select * from emp3
where job = k_job
for update of sal;
v_update_count integer := 0;
v_payroll_increase integer := 0;
begin
for r in employees_cur loop
update emp3 set sal = sal + 100 where current of employees_cur;
dbms_output.put_line('Salary for ' || r.ename || ' is incremented by $100 from $' || r.sal || ' to $' || (r.sal +100));
v_update_count := v_update_count + 1;
v_payroll_increase := v_payroll_increase + 100;
end loop;
if v_update_count = 0 then
dbms_output.put_line('No staff are currently employed as ' || k_job ||'. Payroll is unchanged.');
else
dbms_output.put_line('Updated salary of '|| v_update_count ||' employee' || case when v_update_count <> 1 then 's' end||'.');
dbms_output.put_line('Payroll increased by $'||v_payroll_increase||'.');
end if;
end;
/
Enter value for job: SALESMAN
Salary for ALLEN is incremented by $100 from $1600 to $1700
Salary for WARD is incremented by $100 from $1250 to $1350
Salary for MARTIN is incremented by $100 from $1250 to $1350
Salary for TURNER is incremented by $100 from $1500 to $1600
Updated salary of 4 employees.
Payroll increased by $400.
PL/SQL procedure successfully completed.
For a nonexistent job, you get this:
Enter value for job: ASTRONAUT
No staff are currently employed as ASTRONAUT. Payroll is unchanged.
(In this example, v_payroll_increase is always 100 times v_update_count, but if you wanted to give a 10% raise or differing increases by department etc it might be more useful.)
Here's one option: check whether such a job exists; if not, query will return NO_DATA_FOUND which you can handle and raise an exception with appropriate message. Otherwise, proceed with the UPDATE.
SQL> declare
2 l_job emp.job%type;
3 begin
4 begin
5 select job
6 into l_job
7 from emp
8 where job = '&ENTER_Job'
9 and rownum = 1;
10 exception
11 when no_data_found then
12 raise_application_error(-20000, 'That job does not exist');
13 end;
14
15 -- Job exists, so - go on with the update
16 end;
17 /
Enter value for enter_job: MANAGER
PL/SQL procedure successfully completed.
SQL> /
Enter value for enter_job: DEVELOPER
declare
*
ERROR at line 1:
ORA-20000: That job does not exist
ORA-06512: at line 12
SQL>
P.S. Forgot to mention: I prefer doing such a job through a stored procedure (which accepts job name as a parameter) instead of an anonymous PL/SQL block.

How to remove ORA-01562: Failed to extend rollback segment error while updating 100 million rows

A table is having 100 million records and I need to update a column by adding 10% into the salary of each employee. when I execute update statement I am getting this error:
ORA-01562: Failed to extend rollback segment
How can I update this column for the best performance result?
update employee
set salary = salary + (salary*10/100)
OR
declare
i number(10);
limit number(10) := 100000;
begin
for i in 1 .. limit loop
update employee
set salary = salary + (salary*10/100)
where rownum = i;
limit := limit + 100000;
end loop;
end;
Looks like you are using Oracle version 8i or prior, as the rollback segments have been replaced with undo segments from Oracle 9i onwards.
To solve the problem, I would suggest you to check the trace file to see which rollback segment is creating the problem, then create a bigger rollback segment depending upon the update transaction size.
Try this:
DECLARE
CURSOR CUR
IS
SELECT ROWID, A.*
FROM YOUR_SALARY_TABLE A;
TYPE CUR_TYPE IS TABLE OF CUR%ROWTYPE
INDEX BY PLS_INTEGER;
L_CUR CUR_TYPE;
LIM NUMBER := 100000; -- Update chunk size
BEGIN
OPEN CUR;
LOOP
FETCH CUR BULK COLLECT INTO L_CUR LIMIT LIM;
FOR INDX IN 1 .. L_CUR.COUNT
LOOP
UPDATE YOUR_SALARY_TABLE S
SET S.SALARY_COLUMN = S.SALARY_COLUMN * 2 -- Multiplying here
WHERE ROWID = L_CUR (INDX).ROWID;
END LOOP;
COMMIT;
EXIT WHEN L_CUR.COUNT < LIM;
END LOOP;
CLOSE CUR;
END;
You can try this approach: link
Information about parallel: link
We can use FORALL also to achieve what is required. Hope this below snippet helps.
DROP TABLE test_so1
/
CREATE TABLE TEST_SO1
( COL1 NUMBER, COL2 VARCHAR2(100)
)
/
--Insert values
INSERT INTO TEST_SO1
SELECT LEVEL,'AVRAJIT'||LEVEL FROM DUAL CONNECT BY LEVEL < 10000
/
--FORALL UPDATE
DECLARE
type TEST_REC
IS
RECORD
(
COL1 NUMBER,
COL2 VARCHAR2(100),
col3 VARCHAR2(100));
type TEST_TAB
IS
TABLE OF TEST_REC;
LV_TAB TEST_TAB;
CURSOR LV_CUR
IS
SELECT col1,col2,rowid FROM TEST_SO1;
BEGIN
OPEN LV_CUR;
LOOP
FETCH LV_CUR BULK COLLECT INTO LV_TAB LIMIT 1000;
EXIT
WHEN LV_TAB.COUNT=0;
FORALL I IN LV_TAB.FIRST..LV_TAB.LAST
UPDATE TEST_SO1 SET COL2 = 'shubhojit' WHERE ROWID = lv_tab(i).col3;
COMMIT;
END LOOP;
END;
/

Resources