I would like to load data into a collection from various cursors. and below you can see a small example of the same. To simply put, I need to take columns from various tables and load it into a single table. Initially we were using a direct insert statement which was working fine, however it is causing issues recently. So we are trying to introduce a collection which would collect the data and from there we will load the data to the table.
declare
vin date;
cursor c1 is select emp_id.. from emp;
cursor c2 is select dept_id , ... from dept;
type t3 is table of t%rowtype;
t1 t3 := t3();
begin
for i in (select emp_id,dept_id,vin from dual)
loop
t1.extend;
t1(t1.count).load_date := i.vin;
t1(t1.count).emp_id := i.emp_id;
t1(t1.count).dept_no := i.dept_id;
end loop;
forall j in 1..t1.last
insert into t values (t1(j).emp_id,t1(j).dept_id,t1(j).load_date);
end;
When i tried to run this one, I'm getting an error stating PLS00308 :that constructor is not allowed as the origin of the assignment. Kindly help me on this.
Try it like below:
SET SERVEROUTPUT ON
Declare
TYPE type_a_tbl is Table Of A_TBL%ROWTYPE INDEX BY BINARY_INTEGER;
i BINARY_INTEGER := 0;
tab_a_tbl type_a_tbl;
--
CURSOR c IS
Select e.EMPNO, e.ENAME, d.DEPTNO, d.DNAME, d.LOC, e.MGR
From EMP e
Inner Join DEPT d ON(d.DEPTNO = e.DEPTNO)
Where d.DEPTNO = 30;
cSet c%ROWTYPE;
--
Begin
OPEN c;
LOOP
FETCH c Into cSet;
EXIT WHEN c%NOTFOUND;
i := i + 1;
tab_a_tbl(i).EMPNO := cSet.EMPNO;
tab_a_tbl(i).ENAME := cSet.ENAME;
tab_a_tbl(i).DEPTNO := cSet.DEPTNO;
tab_a_tbl(i).DNAME := cSet.DNAME;
tab_a_tbl(i).LOC := cSet.LOC;
tab_a_tbl(i).MGR := cSet.MGR;
--
Insert Into A_TBL VALUES(tab_a_tbl(i).EMPNO,
tab_a_tbl(i).ENAME,
tab_a_tbl(i).DEPTNO,
tab_a_tbl(i).DNAME,
tab_a_tbl(i).LOC,
tab_a_tbl(i).MGR);
dbms_output.put_line('Row inserted: --> ' || tab_a_tbl(i).EMPNO || Chr(9) || Chr(9) ||
LPAD(tab_a_tbl(i).ENAME, 8, ' ') || Chr(9) || Chr(9) ||
tab_a_tbl(i).DEPTNO || Chr(9) || Chr(9) ||
tab_a_tbl(i).DNAME || Chr(9) || Chr(9) ||
tab_a_tbl(i).LOC || Chr(9) || Chr(9) ||
tab_a_tbl(i).MGR);
--
END LOOP;
CLOSE c;
End;
/
/*
anonymous block completed
Row inserted: --> 7499 ALLEN 30 SALES CHICAGO 7698
Row inserted: --> 7521 WARD 30 SALES CHICAGO 7698
Row inserted: --> 7654 MARTIN 30 SALES CHICAGO 7698
Row inserted: --> 7698 BLAKE 30 SALES CHICAGO 7839
Row inserted: --> 7844 TURNER 30 SALES CHICAGO 7698
Row inserted: --> 7900 JAMES 30 SALES CHICAGO 7698
*/
... or with two cursors (result is the same)
SET SERVEROUTPUT ON
Declare
TYPE type_a_tbl is Table Of A_TBL%ROWTYPE INDEX BY BINARY_INTEGER;
i BINARY_INTEGER := 0;
tab_a_tbl type_a_tbl;
--
CURSOR depts IS
Select d.DEPTNO, d.DNAME, d.LOC From DEPT d Where DEPTNO = 30;
deptSet depts%ROWTYPE;
--
CURSOR c IS
Select e.EMPNO, e.ENAME, e.MGR
From EMP e
Where e.DEPTNO = deptSet.DEPTNO;
cSet c%ROWTYPE;
--
Begin
OPEN depts;
LOOP
FETCH depts Into deptSet;
EXIT WHEN depts%NOTFOUND;
--
OPEN c;
LOOP
FETCH c Into cSet;
EXIT WHEN c%NOTFOUND;
i := i + 1;
tab_a_tbl(i).EMPNO := cSet.EMPNO;
tab_a_tbl(i).ENAME := cSet.ENAME;
tab_a_tbl(i).DEPTNO := deptSet.DEPTNO;
tab_a_tbl(i).DNAME := deptSet.DNAME;
tab_a_tbl(i).LOC := deptSet.LOC;
tab_a_tbl(i).MGR := cSet.MGR;
--
Insert Into A_TBL VALUES(tab_a_tbl(i).EMPNO,
tab_a_tbl(i).ENAME,
tab_a_tbl(i).DEPTNO,
tab_a_tbl(i).DNAME,
tab_a_tbl(i).LOC,
tab_a_tbl(i).MGR);
dbms_output.put_line('Row inserted: --> ' || tab_a_tbl(i).EMPNO || Chr(9) || Chr(9) ||
LPAD(tab_a_tbl(i).ENAME, 8, ' ') || Chr(9) || Chr(9) ||
tab_a_tbl(i).DEPTNO || Chr(9) || Chr(9) ||
tab_a_tbl(i).DNAME || Chr(9) || Chr(9) ||
tab_a_tbl(i).LOC || Chr(9) || Chr(9) ||
tab_a_tbl(i).MGR);
--
END LOOP;
CLOSE c;
--
END LOOP;
CLOSE depts;
End;
/
Don't use PL/SQL, cursors or collection. Just use INSERT INTO ... SELECT ... and JOIN the tables:
INSERT INTO t (emp_id, dept_id, load_date)
SELECT e.emp_id,
d.dept_id,
SYSDATE -- or the column where you stored the date
FROM emp e
INNER JOIN dept d
ON (e.dept_id = d.dept_id) -- or however you want to join the tables.
Related
I have this task.
I did it but e need to use specific ID (tmp_emp_id EMPLOYEES.EMPLOYEE_ID%TYPE := 118;) or its giving me an error. How I can tell "check every ID".
Write a PL/SQL procedure to update the salary of an employee, provided as a parameter, by 5% if the salary exceeds the mid range of the salary against this job and update up to mid range if the salary is less than the mid range of the salary.
DECLARE
emp_min_salary NUMBER(6,0);
emp_max_salary NUMBER(6,0);
emp_mid_salary NUMBER(6,2);
tmp_salary EMPLOYEES.SALARY%TYPE;
tmp_emp_id EMPLOYEES.EMPLOYEE_ID%TYPE := 118;
tmp_emp_name EMPLOYEES.FIRST_NAME%TYPE;
BEGIN
SELECT min_salary,
max_salary
INTO emp_min_salary,
emp_max_salary
FROM JOBS
WHERE JOB_ID = (SELECT JOB_ID
FROM EMPLOYEES
WHERE EMPLOYEE_ID = tmp_emp_id);
-- calculate mid-range
emp_mid_salary := (emp_min_salary + emp_max_salary) / 2;
-- get salary of the given employee
SELECT salary,first_name
INTO tmp_salary,tmp_emp_name
FROM employees
WHERE employee_id = tmp_emp_id;
-- update salary
IF tmp_salary < emp_mid_salary THEN
UPDATE employees
SET salary = emp_mid_salary
WHERE employee_id = tmp_emp_id;
ELSE
UPDATE employees
SET salary = salary + salary * 5 /100
WHERE employee_id = tmp_emp_id;
END IF;
--display message
IF tmp_salary > emp_mid_salary THEN
DBMS_OUTPUT.PUT_LINE('The employee '||tmp_emp_name||' ID ' || TO_CHAR(tmp_emp_id) ||
' works in salary ' || TO_CHAR(tmp_salary) ||
' which is higher than mid-range of salary ' || TO_CHAR(emp_mid_salary));
ELSIF tmp_salary < emp_mid_salary THEN
DBMS_OUTPUT.PUT_LINE('The employee '||tmp_emp_name||' ID ' || TO_CHAR(tmp_emp_id) ||
' works in salary ' || TO_CHAR(tmp_salary) ||
' which is lower than mid-range of salary ' || TO_CHAR(emp_mid_salary));
ELSE
DBMS_OUTPUT.PUT_LINE('The employee '||tmp_emp_name||' ID ' || TO_CHAR(tmp_emp_id) ||
' works in salary ' || TO_CHAR(tmp_salary) ||
' which is equal to the mid-range of salary ' || TO_CHAR(emp_mid_salary));
END IF;
END;
/
NO_DATA_FOUND is returned by one of SELECT statements you used; can't tell which one, I don't have your data.
However, that can be simplified. Here's an example which shows how you might do that.
Sample data is based on Scott's EMP table.
Mid-salaries (using the same algorithm you used):
SQL> SELECT job, (MIN (sal) + MAX (sal)) / 2 midsal
2 FROM emp
3 GROUP BY job;
JOB MIDSAL
--------- ----------
CLERK 1050 --> I'll be using CLERKS for demonstration
SALESMAN 1425
PRESIDENT 5000
MANAGER 2712,5
ANALYST 3000
Clerks:
SQL> SELECT *
2 FROM employees
3 WHERE job = 'CLERK'
4 ORDER BY ename;
EMPNO ENAME JOB SAL
---------- ---------- --------- ----------
7876 ADAMS CLERK 1100
7900 JAMES CLERK 950
7934 MILLER CLERK 1300 --> salary is higher than mid-salary
7369 SMITH CLERK 800 --> salary is lower than mid-salary
Procedure: it uses MERGE as it does everything in the same step, no need for additional commands.
SQL> CREATE OR REPLACE PROCEDURE p_sal (par_empno IN employees.empno%TYPE)
2 IS
3 BEGIN
4 MERGE INTO employees e
5 USING ( SELECT job, (MIN (sal) + MAX (sal)) / 2 midsal
6 FROM emp
7 GROUP BY job) x
8 ON (e.job = x.job)
9 WHEN MATCHED
10 THEN
11 UPDATE SET
12 e.sal =
13 CASE WHEN e.sal > x.midsal THEN e.sal * 1.05 ELSE x.midsal END
14 WHERE e.empno = par_empno;
15 END;
16 /
Procedure created.
Testing:
SQL> EXEC p_sal(7369);
PL/SQL procedure successfully completed.
SQL> EXEC p_sal(7934);
PL/SQL procedure successfully completed.
SQL> SELECT *
2 FROM employees
3 WHERE job = 'CLERK'
4 ORDER BY ename;
EMPNO ENAME JOB SAL
---------- ---------- --------- ----------
7876 ADAMS CLERK 1100
7900 JAMES CLERK 950
7934 MILLER CLERK 1365 --> 5% raise
7369 SMITH CLERK 1050 --> set to mid-salary
SQL>
Personally I voted the solution of #littlefoot, since he answered properly about the original question of the NO_DATA_FOUND and also shrinked the code in 1 single merge statement as I would too.
I just want to add an alternate version in case you "need" to log salary changes and/or add more business logic for each specific case.
DECLARE
emp_mid_salary NUMBER(6,2);
tmp_salary EMPLOYEES.SALARY%TYPE;
new_salary EMPLOYEES.SALARY%TYPE;
tmp_emp_id EMPLOYEES.EMPLOYEE_ID%TYPE := 118;
tmp_emp_name EMPLOYEES.FIRST_NAME%TYPE;
BEGIN
--single query for extract all data
SELECT (min_salary + max_salary) / 2, salary, first_name
INTO emp_mid_salary, tmp_salary, tmp_emp_name
FROM JOBS J
JOIN EMPLOYEES E
ON J.JOB_ID = E.JOB_ID
WHERE E.EMPLOYEE_ID = tmp_emp_id
;
--business logic
IF tmp_salary > emp_mid_salary THEN
--calcs
new_salary := tmp_salary + tmp_salary * 5 /100;
--output
DBMS_OUTPUT.PUT_LINE('The employee '||tmp_emp_name||' ID ' || TO_CHAR(tmp_emp_id) ||
' works in salary ' || TO_CHAR(tmp_salary) ||
' which is higher than mid-range of salary ' || TO_CHAR(emp_mid_salary));
ELSIF tmp_salary < emp_mid_salary THEN
--calcs
new_salary := emp_mid_salary;
--output
DBMS_OUTPUT.PUT_LINE('The employee '||tmp_emp_name||' ID ' || TO_CHAR(tmp_emp_id) ||
' works in salary ' || TO_CHAR(tmp_salary) ||
' which is lower than mid-range of salary ' || TO_CHAR(emp_mid_salary));
ELSE
--calcs
new_salary := tmp_salary + tmp_salary * 5 /100;
--output
DBMS_OUTPUT.PUT_LINE('The employee '||tmp_emp_name||' ID ' || TO_CHAR(tmp_emp_id) ||
' works in salary ' || TO_CHAR(tmp_salary) ||
' which is equal to the mid-range of salary ' || TO_CHAR(emp_mid_salary));
END IF;
BEGIN
--one single final update
UPDATE employees
SET salary = new_salary
WHERE employee_id = tmp_emp_id;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Failed to update salary to employee with ID ' || TO_CHAR(tmp_emp_id));
--handle/log exception
END;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Could not find a JOB related to the employee with ID ' || TO_CHAR(tmp_emp_id));
WHEN OTHERS THEN
--handle/log exception, in the rare case something went wrong with the calcs?
END;
/
When trying to compile in order to execute both functions(#directory) I keep getting a no data error on line 48. (or line 13 for the function). This is the error i receive. NOTE: SYSTEM is the server I'm connected to.
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "SYSTEM.DEPTPROJECT", line 13
ORA-06512: at line 4
ORA-06512: at line 4
these are my function
SET ECHO ON;
SET FEEDBACK ON;
SET LINESIZE 100;
SET PAGESIZE 100;
SET SERVEROUTPUT ON;
CREATE OR REPLACE FUNCTION DEPTPROJECT(departmentNumber IN NUMBER)
RETURN VARCHAR IS
dep# DEPARTMENT.D#%TYPE;
depName DEPARTMENT.DName%TYPE;
counter NUMBER(10,0);
empNumber CHAR(5);
empName VARCHAR2(30);
result VARCHAR2(600);
BEGIN
SELECT D#, DNAME INTO dep#, depName FROM DEPARTMENT WHERE DEPARTMENT.D# = dep#;
result := result || 'Department'|| dep# || '' || depName || chr (10);
FOR i IN(SELECT P# , PTitle , Budget FROM PROJECT WHERE PROJECT.D# = dep# ORDER BY BUDGET DESC)
LOOP
result:= result || chr(9)|| 'Project: ' || i.P# || '' || i.PTitle || i.Budget || chr(10);
FOR j IN(SELECT EMPLOYEE.Name, EMPLOYEE.E# FROM WORKSON INNER JOIN EMPLOYEE ON EMPLOYEE.E# = WORKSON.E# WHERE WORKSON.P# = i.P# ORDER BY EMPLOYEE.NAME ASC )
LOOP
result:= result || chr(10) || j.E# || '' || j.Name || chr(10);
END LOOP;
END LOOP;
RETURN result;
END;
/
BEGIN
FOR x IN(SELECT D# FROM DEPARTMENT)
LOOP
DBMS_OUTPUT.PUT_LINE(DEPTPROJECT(x.D#));
END LOOP;
END;
/
When you are selecting INTO a variable and there are no records returned you should get a NO DATA FOUND error. I believe the correct way to write the above code would be to wrap the SELECT statement with it's own BEGIN/EXCEPTION/END block.
Example:
SET ECHO ON;
SET FEEDBACK ON;
SET LINESIZE 100;
SET PAGESIZE 100;
SET SERVEROUTPUT ON;
CREATE OR REPLACE FUNCTION DEPTPROJECT(departmentNumber IN NUMBER)
RETURN VARCHAR IS
dep# DEPARTMENT.D#%TYPE;
depName DEPARTMENT.DName%TYPE;
counter NUMBER(10,0);
empNumber CHAR(5);
empName VARCHAR2(30);
result VARCHAR2(600);
BEGIN
SELECT D#, DNAME INTO dep#, depName FROM DEPARTMENT WHERE DEPARTMENT.D# = departmentNumber;
result := result || 'Department'|| dep# || '' || depName || chr (10);
FOR i IN(SELECT P# , PTitle , Budget FROM PROJECT WHERE PROJECT.D# = dep# ORDER BY BUDGET DESC)
LOOP
result:= result || chr(9)|| 'Project: ' || i.P# || '' || i.PTitle || i.Budget || chr(10);
FOR j IN(SELECT EMPLOYEE.Name, EMPLOYEE.E# FROM WORKSON INNER JOIN EMPLOYEE ON EMPLOYEE.E# = WORKSON.E# WHERE WORKSON.P# = i.P# ORDER BY EMPLOYEE.NAME ASC )
LOOP
result:= result || chr(10) || j.E# || '' || j.Name || chr(10);
END LOOP;
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
result := 'Record Not Found';
RETURN result;
END;
/
BEGIN
FOR x IN(SELECT D# FROM DEPARTMENT)
LOOP
DBMS_OUTPUT.PUT_LINE(DEPTPROJECT(x.D#));
END LOOP;
END;
/
I'd guess that line 13 should use the variable being passed to the function:
SELECT D#, DNAME INTO dep#, depName FROM DEPARTMENT WHERE DEPARTMENT.D# = dep#;
Should be:
SELECT D#, DNAME INTO dep#, depName FROM DEPARTMENT WHERE DEPARTMENT.D# = departmentNumber;
You are using following query to fetch dep# and depName but your where clause is WHERE DEPARTMENT.D# = dep# .
SELECT D#, DNAME INTO dep#, depName FROM DEPARTMENT WHERE DEPARTMENT.D# = dep#;
Here dep# is a variable which you have declared but not initialized.
So dep# is null and comparision to NULL will always lead to false which means your query is returning no record.
As you have used INTO in your query, Oracle is seeking for exactly one record from this query but it is returning no records. Hence, you are facing the issue.
According to your logic either change the WHERE clause to include departmentNumber in comparision or assign proper value to dep# before using it in your query.
Also, make sure to wrap your SELECT .. INTO query in BEGIN..EXCEPTION..END to avoid such a dynamic exception.
Cheers!!
can't make this work... have a multiple tables names which i need to pass into select. Each select will return multiple records. Resultset should be printed to the user on a screen .
SQL> set serveroutput on;
SQL> DECLARE
vs_statement VARCHAR2 (1000);
my_var1 VARCHAR2(100);
my_var2 VARCHAR2(100);
CURSOR c1 IS
SELECT table_name
FROM all_tables
WHERE table_name LIKE Upper('redit_1%');
BEGIN
FOR table_rec IN c1 LOOP
vs_statement :=
'select a.userinfo, a.userstatus into my_var1, my_var12 from '
|| table_rec.table_name
|| ' A, FILES b where A.objectid = B.id order by 1';
EXECUTE IMMEDIATE vs_statement INTO my_var1,
my_var2;
dbms_output.Put_line(my_var1
||' '
|| my_var2);
END LOOP;
END;
/
This line should look like the following (i.e. remove INTO clause):
vs_statement :=
'select a.userinfo, a.userstatus from '
|| table_rec.table_name
|| ' A, FILES b where A.objectid = B.id order by 1';
Also, make sure that this SELECT returns only 1 row, otherwise you'll end up with the TOO-MANY-ROWS error.
Other than that, I guess it should work.
[EDIT, regarding fear of TOO-MANY-ROWS]
Huh, I'd create a whole new PL/SQL BEGIN-END block, containing a loop which would do the job, displaying all rows returned by SELECT statement.
As I don't have your tables, I used HR's. Have a look:
SQL> DECLARE
2 vs_statement VARCHAR2 (1000);
3 my_var1 VARCHAR2(100);
4 my_var2 VARCHAR2(100);
5 CURSOR c1 IS
6 SELECT table_name
7 FROM all_tables
8 WHERE table_name LIKE Upper('%departments%');
9 BEGIN
10 FOR table_rec IN c1 LOOP
11 vs_statement := 'begin for cur_r in ( '
12 || Chr(10)
13 || 'select distinct a.department_id, a.department_name from '
14 || Chr(10)
15 || table_rec.table_name
16 ||
17 ' A, employees b where A.department_id = B.department_id order by 1) loop'
18 || Chr(10)
19 || ' dbms_output.put_line(cur_r.department_name); '
20 || Chr(10)
21 || ' end loop; end;';
22
23 EXECUTE IMMEDIATE vs_statement; -- into my_var1, my_var2;
24 END LOOP;
25 END;
26 /
Administration
Marketing
Purchasing
Human Resources
Shipping
IT
Public Relations
Sales
Executive
Finance
Accounting
PL/SQL procedure successfully completed.
SQL>
"Each select will return multiple records...Resultset should be printed to the user on a screen"
Open a ref cursor for each generated statement. Loop round that and display the values.
DECLARE
rc sys_refcursor;
vs_statement VARCHAR2 (1000);
my_var1 VARCHAR2(100);
my_var2 VARCHAR2(100);
CURSOR c1 IS
SELECT table_name
FROM all_tables
WHERE table_name LIKE Upper('redit_1%');
BEGIN
<< tab_loop >>
FOR table_rec IN c1 LOOP
vs_statement :=
'select a.userinfo, a.userstatus from '
|| table_rec.table_name
|| ' A, FILES b where A.objectid = B.id order by 1';
open rc for vs_statement;
dbms_output.put_line('records for '||table_rec.table_name);
<< rec_loop >>
loop
fetch rc into my_var1,my_var2;
exit when rc%notfound;
dbms_output.Put_line(my_var1
||' '
|| my_var2);
end loop rec_loop;
close rc;
END LOOP tab_loop;
END;
/
I have a table with two rows and I need to copy some data in row A to row B.
My biggest concern here is that the columns involved are not static in name or number (table can grow or shrink in column number).
I came up with a solution that i don't like at all...
create or replace
PROCEDURE Z_COPY_TASK_ATT_PE
(
par_oldRowId IN VARCHAR2,
par_newRowId IN VARCHAR2
)
IS
var_update VARCHAR2(4000 BYTE);
var_crr_col_value_old VARCHAR2(10 BYTE);
var_crr_select VARCHAR2(4000 BYTE);
BEGIN
var_update := 'UPDATE PLANNING_ENTITY SET ';
for i in (
Select COLUMN_NAME
from user_tab_columns
where table_name='PLANNING_ENTITY'
and lower(COLUMN_NAME) like 'code%'
)
loop
var_crr_select := 'select ' || i.column_name
|| ' from planning_entity where planning_code = '''
|| par_oldRowId || '''';
execute immediate var_crr_select
into var_crr_col_value_old;
var_update := var_update || i.column_name || ' = ''' || var_crr_col_value_old || ''', ';
end loop;
var_update := SUBSTR(var_update, 0, length(var_update)-2 );
var_update := var_update || ' where planning_code = ''' || par_newRowId || '''';
execute immediate var_update;
commit;
END;
My major issue here (for me at least) is the fact that i need to make the select for each iteration of the loop. It would be really nice if i could make a select that returned something like column|name and then all I needed to do was i.column and i.value.
What do you think?
===== Solution following Marmite Bomber Answer =====
create or replace
PROCEDURE Z_COPY_TASK_ATT_PE
(
par_oldRowId IN VARCHAR2,
par_newRowId IN VARCHAR2
)
IS
var_update VARCHAR2(4000 BYTE);
var_columns varchar2(4000 BYTE);
BEGIN
Select LISTAGG(COLUMN_NAME, ',') WITHIN group (order by column_name) into var_columns
from user_tab_columns
where table_name='PLANNING_ENTITY'
and lower(COLUMN_NAME) like 'code%';
var_update := 'UPDATE PLANNING_ENTITY PE1 SET (' || var_columns ||
') = (SELECT ' || var_columns || ' FROM PLANNING_ENTITY PE2 WHERE PE2.PLANNING_CODE = ''' || par_oldRowId ||
''') WHERE PE1.PLANNING_CODE = ''' || par_newRowId || '''';
execute immediate var_update;
commit;
END;
Based on this update
UPDATE t1 a
SET (code1, code2) = (
SELECT code1,code2
FROM t1 b
WHERE b.planning_code = 'new')
where a.planning_code = 'old';
you need only generate comma separated list of the column names that should be updated and apply it twice in the statement. In the example code1,code2.
How about this?
begin
for i in (select * from PLANNING_ENTITY where planning_code = newrow) loop
update PLANNING_ENTITY set row = i where planning_code = oldrow;
end loop;
end;
For downvoters:
SQL> select version from v$instance;
VERSION
-----------------
11.2.0.4.0
SQL> create table it_works_in_oracle (n1 number, n2 number, n3 number);
Table created.
SQL> insert into it_works_in_oracle values(1, 1, 1);
1 row created.
SQL> insert into it_works_in_oracle values(2, 2, 2);
1 row created.
SQL> insert into it_works_in_oracle values(3, 3, 3);
1 row created.
SQL> commit;
Commit complete.
SQL> select * from it_works_in_oracle;
N1 N2 N3
---------- ---------- ----------
1 1 1
2 2 2
3 3 3
SQL> set serveroutput on
SQL> declare
oldrow number:=1;
newrow number:=3;
begin
for i in (select * from it_works_in_oracle where n1 = newrow) loop
update it_works_in_oracle set row = i where n1 = oldrow;
end loop;
end; 2 3 4 5 6 7 8
9 /
PL/SQL procedure successfully completed.
SQL> select * from it_works_in_oracle;
N1 N2 N3
---------- ---------- ----------
3 3 3
2 2 2
3 3 3
You can do it similar to this (not tested):
var_update := 'UPDATE PLANNING_ENTITY a SET (';
FOR i IN (
SELECT COLUMN_NAME
FROM USER_TAB_COLUMNS
WHERE table_name='PLANNING_ENTITY'
AND LOWER(COLUMN_NAME) LIKE 'code%'
)
LOOP
var_update := var_update || i.column_name ||',';
END LOOP;
var_update := REGEXP_REPLACE(var_update, ',$', ')');
var_update := var_update ||' = (SELECT ';
FOR i IN (
SELECT COLUMN_NAME
FROM USER_TAB_COLUMNS
WHERE table_name='PLANNING_ENTITY'
AND LOWER(COLUMN_NAME) LIKE 'code%'
)
LOOP
var_update := var_update || i.column_name ||',';
END LOOP;
var_update := REGEXP_REPLACE(var_update, ',$');
var_update := var_update || ' FROM PLANNING_ENTITY b WHERE planning_code = :newRowId) ';
var_update := var_update || ' WHERE a.planning_code = :oldRowId';
EXECUTE IMMEDIATE var_update USING par_newRowId, par_oldRowId;
So i have this:
CREATE OR REPLACE PACKAGE my_first_package
IS
PROCEDURE employee_analysis
(p_id IN NUMBER := 100, /*default formal parameter with no arguments for invokation */
p_percent IN NUMBER := 0.01); /* -||- */
END my_first_package;
CREATE OR REPLACE PACKAGE BODY my_first_package
IS
PROCEDURE employee_analysis
(p_id IN NUMBER := 100,
p_percent IN NUMBER := 0.01)
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);
/*-----------------------------------------------------------------------------*/
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);
v_old_salary NUMBER(9,2);
v_new_salary NUMBER(9,2);
v_lname VARCHAR2(10);
v_phone_number_format VARCHAR2(25);
v_phone_number_length NUMBER(3);
v_tax NUMBER(8,4);
v_sum_sal_departments NUMBER;
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, LENGTH(phone_number)
INTO v_monthly_sal, v_last_name, v_deptno,
v_tenure, v_job_id, v_hire_date, v_commission_pct,
v_phone_number, v_email, v_phone_number_length
FROM employees
WHERE employee_id = p_id;
/*-----------------------------------------------------------------------------*/
v_count := SQL%ROWCOUNT;
DBMS_OUTPUT.PUT_LINE(v_count||' Employee found...');
/*-----------------------------------------------------------------------------*/
v_annual_sal := v_monthly_sal * 12;
v_length := LENGTH(v_last_name);
DBMS_OUTPUT.PUT_LINE('Employee:-> ' || v_last_name || ' ,and his name contains: ' || v_length ||' chars');
DBMS_OUTPUT.PUT_LINE(q'[Belong's to department: ]' || v_deptno);
/*-----------------------------------------------------------------------------*/
IF (v_monthly_sal < v_annual_sal)
THEN
DBMS_OUTPUT.PUT_LINE('Has a annual salary of:-> ' || v_annual_sal);
ELSE
DBMS_OUTPUT.PUT_LINE('Something wrong in the formula!');
END IF;
/*-------------------------------------------------------------------------------*/
IF 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:-> '|| v_commission_pct ||'%');
v_comm_calc := (v_annual_sal * v_commission_pct) + v_annual_sal;
DBMS_OUTPUT.PUT_LINE('And calculated with annual salary is:-> ' ||v_comm_calc);
END IF;
/*-------------------------------------------------------------------------------*/
DBMS_OUTPUT.PUT_LINE('Working for:-> '|| v_tenure || ' months as '|| v_job_id);
DBMS_OUTPUT.PUT_LINE('Started in:-> '|| v_hire_date);
/*-------------------------------------------------------------------------------*/
IF v_phone_number_length = 12
THEN
v_phone_number_format := '(' || SUBSTR(v_phone_number,1,3) || ')' ||
'-' || SUBSTR(v_phone_number,5,3) ||
'-' || SUBSTR(v_phone_number,9,4);
DBMS_OUTPUT.PUT_LINE('Phone number:-> '|| v_phone_number_format);
ELSIF v_phone_number_length = 18
THEN
v_phone_number_format := '(' || SUBSTR(v_phone_number,1,3) || ')' ||
'-' || SUBSTR(v_phone_number,5,2) ||
'-' || SUBSTR(v_phone_number,8,4) || '-'
|| SUBSTR(v_phone_number,13,6);
DBMS_OUTPUT.PUT_LINE('Phone number:-> '|| v_phone_number_format);
ELSE
DBMS_OUTPUT.PUT_LINE('Phone number digits not in range, check the length of the phone numbers from the table');
END IF;
/*-------------------------------------------------------------------------------*/
DBMS_OUTPUT.PUT_LINE('Email:-> '||v_email);
/*-------------------------------------------------------------------------------*/
OPEN c_city;
FETCH c_city
INTO v_city;
IF c_city%FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Location:-> '||v_city);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee location unknown');
END IF;
CLOSE c_city;
/*-------------------------------------------------------------------------------*/
OPEN c_manager;
FETCH c_manager
INTO v_manager;
IF c_manager%FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Is in the eyes of manager:-> '||v_manager);
ELSE
DBMS_OUTPUT.PUT_LINE('Slave '||v_last_name||' is free!');
END IF;
CLOSE c_manager;
/*-------------------------------------------------------------------------------*/
OPEN c_department_name;
FETCH c_department_name
INTO v_department;
IF c_department_name%FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Department Name:-> '||v_department);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee ' ||v_last_name||' belongs to no department!');
END IF;
/*--------------------------------------------------------------------------------*/
DBMS_OUTPUT.PUT_LINE('Checking the current 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 '||v_deptno||' where he belongs.');
ELSE
DBMS_OUTPUT.PUT_LINE('Salary < average of department '||v_deptno||', where he belongs.');
END IF;
/*--------------------------------------------------------------------------------*/
SELECT salary
INTO v_old_salary
FROM employees
WHERE employee_id = p_id;
DBMS_OUTPUT.PUT_LINE('Before the raise of ' || p_percent ||
' %, the salary was:-> '|| v_old_salary);
/*--------------------------------------------------------------------------------*/
IF (p_percent > 0.01)
THEN
DBMS_OUTPUT.PUT_LINE('Maximum increase allowance for the moment is only 0.01 %, thus no increase in salary is made');
ELSIF (p_percent < 0.01)
THEN
DBMS_OUTPUT.PUT_LINE('Minimum percent allowance for the moment is only 0.01 %, thus no increase in salary is made');
ELSE
UPDATE employees
SET salary = salary * (1 + p_percent/100)
WHERE employee_id = p_id;
SELECT last_name, salary
INTO v_lname, v_new_salary
FROM employees
WHERE employee_id = p_id;
DBMS_OUTPUT.PUT_LINE('After the raise of ' || p_percent ||
' %, the salary is:-> '|| v_new_salary);
END IF;
/*--------------------------------------------------------------------------------*/
DBMS_OUTPUT.PUT_LINE('===========================================================');
DBMS_OUTPUT.PUT_LINE('===========================================================');
DBMS_OUTPUT.PUT_LINE('===========================================================');
FOR i IN (SELECT SUM(salary) AS "SUMY", department_id
FROM employees
GROUP BY department_id)
LOOP
IF i.department_id IS NULL
THEN
DBMS_OUTPUT.PUT_LINE('Unknown department '|| i.department_id ||' earns:-> '|| i.sumy);
ELSE
DBMS_OUTPUT.PUT_LINE('Department '|| i.department_id ||' earns:-> '|| i.sumy);
END IF;
END LOOP;
FOR j IN (SELECT SUM(sumy) AS "DEP_SUM"
FROM (SELECT SUM(salary) AS "SUMY"
FROM employees
GROUP BY department_id))
LOOP
v_sum_sal_departments := j.dep_sum;
DBMS_OUTPUT.PUT_LINE('Total income on all departments:-> '|| j.dep_sum);
END LOOP;
SELECT taxes_pkg.tax(salary)
INTO v_tax
FROM employees
WHERE employee_id = p_id;
DBMS_OUTPUT.PUT_LINE('Salary after 0.08 % tax withdrawal:-> '|| v_tax);
FOR k IN (SELECT last_name
FROM employees
WHERE salary = (SELECT MAX(salary)
FROM employees))
LOOP
DBMS_OUTPUT.PUT_LINE('Employee with the highest salary is:-> '||k.last_name);
END LOOP;
FOR k IN (SELECT last_name, hire_date
FROM employees
WHERE hire_date = (SELECT MAX(hire_date)
FROM employees))
LOOP
DBMS_OUTPUT.PUT_LINE('Our newest employees are:-> ' || k.last_name);
END LOOP;
FOR m IN (SELECT last_name
FROM employees
WHERE hire_date = (SELECT MIN(hire_date)
FROM employees))
LOOP
DBMS_OUTPUT.PUT_LINE('Our oldest employees are:-> '||m.last_name);
END LOOP;
/*--------------------------------------------------------------------------------*/
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Employee with id:-> ' || p_id || ' does not exist, check data from your tables!');
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('Unknown propagation');
END employee_analysis;
END my_first_package;
I seached about something called utl_file package for exporting data from oracle database and so on, but i didn't understand much and didn't found what i was looking for. Basically what i want is, how can i "export" all of the output from the screen after running this useless package above? Is there a way to modify the package add features and stuff to it? It is possible? Thanks...