I have multiple report pages. I am working on a system that stores a lot of data. Is it possible to have reports that are able to have column edited on two different reports?
i.e. Not all the information may be relevant to the person entering data on the interactive grid. So I would have a condensed version of the report where the would be able to enter the data you are responsible for. But the report would still display the information entered on the condensed report version.
I'd think of a view and its instead of trigger.
Here's an example; see if you can adjust it to interactive grid. It is based on Scott's sample EMP and DEPT tables.
First, a view that joins these two tables:
SQL> create or replace view v_emp_dept as
2 select d.deptno, d.dname, e.empno, e.ename, e.job, e.sal
3 from emp e join dept d on d.deptno = e.deptno;
View created.
Instead of trigger; it fires when you update the view, but in the background it modifies data in view's underlying tables:
SQL> create or replace trigger trg_iu_ved
2 instead of update on v_emp_dept
3 for each row
4 begin
5 update dept d set
6 d.dname = :new.dname
7 where d.deptno = :new.deptno;
8
9 update emp e set
10 e.ename = :new.ename,
11 e.job = :new.job,
12 e.sal = :new.sal
13 where e.empno = :new.empno;
14 end;
15 /
Trigger created.
OK, let's test it. Sample data:
SQL> select * from v_emp_dept where deptno = 10;
DEPTNO DNAME EMPNO ENAME JOB SAL
---------- -------------- ---------- ---------- --------- ----------
10 ACCOUNTING 7782 CLARK MANAGER 2818
10 ACCOUNTING 7839 KING PRESIDENT 5750
10 ACCOUNTING 7934 MILLER CLERK 1495
Update some values:
SQL> update v_emp_dept set
2 dname = 'Accounting',
3 ename = initcap(ename),
4 sal = sal * 10
5 where deptno = 10;
3 rows updated.
Oracle says that 3 rows were updated:
SQL> select * from v_emp_dept where deptno = 10;
DEPTNO DNAME EMPNO ENAME JOB SAL
---------- -------------- ---------- ---------- --------- ----------
10 Accounting 7782 Clark MANAGER 28180
10 Accounting 7839 King PRESIDENT 57500
10 Accounting 7934 Miller CLERK 14950
The view looks OK. What about EMP and DEPT tables?
SQL> select * from dept where deptno = 10;
DEPTNO DNAME LOC
---------- -------------- -------------
10 Accounting NEW YORK
SQL> select empno, ename, job, sal from emp where deptno = 10;
EMPNO ENAME JOB SAL
---------- ---------- --------- ----------
7782 Clark MANAGER 28180
7839 King PRESIDENT 57500
7934 Miller CLERK 14950
SQL>
Right; data has been changed in these two tables as well.
Related
This question already has an answer here:
Select * from subquery
(1 answer)
Closed 24 days ago.
I need to create a function which will show all the columns of this join but depending on a parameter, an extra column is added to the query. To show you how it works
This is the original query
SELECT * FROM bf_uom.V_BF_JOBS_STATUS Bj
left join bf_uom.bf_runs r
on bj.run_id = r.run_id
LEFT JOIN bf_uom.Bf_Document_Catalog Bdc
ON
bf_uom.Bj.Document_Label = Bdc.Document_Label
left join bf_uom.bf_load_jobs lj
on lj.job_id=bj.job_id WHERE lj.job_id =:JOB_ID
But, if the input parameter is met, an extra column should be added to the query, like this
SELECT 'DOWNLOAD PDF' as "DOWNLOAD",* FROM bf_uom.V_BF_JOBS_STATUS Bj
left join bf_uom.bf_runs r
on bj.run_id = r.run_id
LEFT JOIN bf_uom.Bf_Document_Catalog Bdc
ON
bf_uom.Bj.Document_Label = Bdc.Document_Label
left join bf_uom.bf_load_jobs lj
on lj.job_id=bj.job_id WHERE lj.job_id =:JOB_ID
This of course doesn't work, I tried with adding tables.* instead of *, but it still doesn't show the same number of columns as SELECT *.
How to solve this without typing the names of all columns that should be in the SELECT statement?
How to solve this without typing the names of all columns that should be in the SELECT statement?
And yet, that's exactly what you should be doing.
Anyway, if you insist on bad practice, then this is what works:
SQL> select *
2 from dept d left join emp e on e.deptno = d.deptno;
DEPTNO DNAME LOC EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- -------------- ------------- ---------- ---------- --------- ---------- -------- ---------- ---------- ----------
10 ACCOUNTING NEW YORK 7782 CLARK MANAGER 7839 09.06.81 2450 10
10 ACCOUNTING NEW YORK 7839 KING PRESIDENT 17.11.81 5000 10
10 ACCOUNTING NEW YORK 7934 MILLER CLERK 7782 23.01.82 1300 10
<snip>
15 rows selected.
This is what doesn't work:
SQL> select 'download pdf' as download, *
2 from dept d left join emp e on e.deptno = d.deptno;
select 'download pdf' as download, *
*
ERROR at line 1:
ORA-00936: missing expression
If you specify all tables (along with the asterisk), then it works but - once again - that's bad practice:
SQL> select 'download pdf' as download, d.*, e.*
2 from dept d left join emp e on e.deptno = d.deptno;
DOWNLOAD DEPTNO DNAME LOC EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
------------ ---------- -------------- ------------- ---------- ---------- --------- ---------- -------- ---------- ---------- ----------
download pdf 10 ACCOUNTING NEW YORK 7782 CLARK MANAGER 7839 09.06.81 2450 10
download pdf 10 ACCOUNTING NEW YORK 7839 KING PRESIDENT 17.11.81 5000 10
download pdf 10 ACCOUNTING NEW YORK 7934 MILLER CLERK 7782 23.01.82 1300 10
<snip>
15 rows selected.
SQL>
In your case, you'd
SELECT 'DOWNLOAD PDF' as "DOWNLOAD", bj.*, r.*, bdc.*
We have multiple .sql files and is there any way we can run them in single job ?
Sample files.
#task1.sql ;
#task2.sql ;
#task3.sql ;
Is there any way can I put all 3 above files in single files and run?
Well ... yes.
task_main.sql:
#task1.sql
#task2.sql
task1.sql:
select deptno, ename, job, sal
from emp
where deptno = 10;
task2.sql:
select * from dept;
Running task_main from SQL*Plus:
SQL> #task_main
DEPTNO ENAME JOB SAL
---------- ---------- --------- ----------
10 CLARK MANAGER 2450
10 KING PRESIDENT 5000
10 MILLER CLERK 1300
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>
So i want to hire a new manager for a department. This procedure has 2 parameters, the department name i want to change, and the new id for manager (taken from employee's id). So to change it, i need to update all employee that has the old manager id, and change their manager id into the new one. This is my code so far, the problem is that it updated all of the employees' manager, so the whole database is updated. I must use procedure, not function. Any idea? Thanks.
CREATE OR REPLACE PROCEDURE update_manager(v_deptname IN departments.department_name%TYPE,v_empid IN employees.employee_id%TYPE) IS
v_deptid departments.department_id%type;
BEGIN
SELECT department_id INTO v_deptid FROM departments WHERE department_name=v_deptname;
FOR i IN (SELECT * FROM employees)
LOOP
IF i.department_id=v_deptid THEN
UPDATE employees
SET manager_id=v_empid
WHERE i.department_id=v_deptid;
END IF;
END LOOP;
END;
/
BEGIN
update_manager('Marketing',100);
END;
/
If you must create a PL/SQL procedure then you can do
CREATE OR REPLACE PROCEDURE update_manager(v_deptname IN departments.department_name%TYPE,v_empid IN employees.employee_id%TYPE) IS
v_deptid departments.department_id%type;
BEGIN
SELECT department_id INTO v_deptid FROM departments WHERE department_name=v_deptname;
UPDATE employees
SET manager_id=v_empid
WHERE department_id=v_deptid;
END;
/
The problem with your code that's causing "it updated all of the employees' manager" is that your update statement:
UPDATE employees
SET manager_id=v_empid
WHERE i.department_id=v_deptid;
Your filter here is comparing i.department_id, this is the variable that's coming from your FOR i IN (SELECT * FROM employees), NOT from the update statement. You've already confirmed that i.department_id=v_deptid because you are calling this in a loop with an if statement checking it.
It is not efficient at all to get all rows in employees, loop the results, checking each row if it matches a condition and then firing off an update statement (even if your update statement is filtering against the correct row.
I don't have your tables, but I do have Scott's so - here's an example.
Departments and employees in department 10:
SQL> select * From dept order by deptno;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> select deptno, empno, ename, mgr
2 from emp
3 where deptno = 10;
DEPTNO EMPNO ENAME MGR
---------- ---------- ---------- ----------
10 7782 CLARK 7839
10 7839 KING
10 7934 MILLER 7782
Procedure that looks like yours (as you're studying PL/SQL), using a variable to fetch department number into, as well as a loop:
SQL> create or replace procedure update_manager
2 (v_deptname in dept.dname%type,
3 v_empno in emp.empno%type
4 )
5 is
6 v_deptno dept.deptno%type;
7 begin
8 select d.deptno
9 into v_deptno
10 from dept d
11 where d.dname = v_deptname; --> this is what you are missing
12
13 for cur_r in (select e.empno
14 from emp e
15 where e.deptno = v_deptno
16 )
17 loop
18 update emp a set
19 a.mgr = v_empno
20 where a.empno = cur_r.empno;
21 end loop;
22 end;
23 /
Procedure created.
Testing: let's modify manager of all employees in department 10:
SQL> exec update_manager ('ACCOUNTING', 7839);
PL/SQL procedure successfully completed.
SQL> select deptno, empno, ename, mgr
2 from emp
3 where deptno = 10;
DEPTNO EMPNO ENAME MGR
---------- ---------- ---------- ----------
10 7782 CLARK 7839
10 7839 KING 7839
10 7934 MILLER 7839
SQL>
Seems to work. Though, that's inefficient; doing it row-by-row (in a loop) is usually slow-by-slow. Work on the whole sets of data, rather. Something like this:
SQL> rollback;
Rollback complete.
SQL> create or replace procedure update_manager
2 (v_deptname in dept.dname%type,
3 v_empno in emp.empno%type
4 )
5 is
6 begin
7 update emp e set
8 e.mgr = v_empno
9 where e.deptno = (select d.deptno
10 from dept d
11 where d.dname = v_deptname
12 );
13 end;
14 /
Procedure created.
SQL> exec update_manager ('ACCOUNTING', 7782);
PL/SQL procedure successfully completed.
SQL> select deptno, empno, ename, mgr
2 from emp
3 where deptno = 10;
DEPTNO EMPNO ENAME MGR
---------- ---------- ---------- ----------
10 7782 CLARK 7782
10 7839 KING 7782
10 7934 MILLER 7782
SQL>
Why not a simple select for manager id and an update on all concerned employee ?
DECLARE #department_id uniqueidentifier
SELECT #department_id = departement_id
FROM departments
WHERE department_name = #v_deptname
UPDATE employees
SET manager_id = #v_empid
WHERE department_id = #department_id
select e.last_name, ee.last_name
from employees e join employees ee on (e.manager_id = ee.employee_id)
where last_name in (select last_name
from employees
where employee_id in (select distinct manager_id
from employees
)
);
If I understood you correctly, you want to select managers only.
The following example is based on Scott's schema.
Here are all employees, along with their managers (hierarchically) so that it is easier to spot the managers.
SQL> select lpad(' ', (level - 1) * 2) || ename ename
2 from emp
3 start with mgr is null
4 connect by prior empno = mgr;
ENAME
------------------------------------------------------
KING -- manager
JONES -- manager
FORD -- manager
SMITH -- employee
BLAKE -- manager
ALLEN -- employee
WARD -- employee
MARTIN -- employee
TURNER -- employee
JAMES -- employee
CLARK -- manager
MILLER -- employee
12 rows selected.
SQL>
Additional WHERE clause returns managers only:
SQL> select lpad(' ', (level - 1) * 2) || ename ename
2 from emp
3 where empno in (select mgr from emp)
4 start with mgr is null
5 connect by prior empno = mgr;
ENAME
--------------------------------------------------------
KING
JONES
FORD
BLAKE
CLARK
SQL>
Substituting what is getting selected with SYS_CONNECT_BY_PATH, we'll get a different output:
SQL> select sys_connect_by_path(ename, ' / ') path
2 from emp
3 where empno in (select mgr from emp)
4 start with mgr is null
5 connect by prior empno = mgr;
PATH
----------------------------------------------------
/ KING
/ KING / JONES
/ KING / JONES / FORD
/ KING / BLAKE
/ KING / CLARK
SQL>
Or, following your steps, with a self-join of the EMP table, we get
SQL> select m1.ename manager, m2.ename his_manager
2 from emp m1 join emp m2 on m1.mgr = m2.empno
3 where m1.empno in (select mgr from emp);
MANAGER HIS_MANAGER
---------- -------------
FORD JONES
CLARK KING
BLAKE KING
JONES KING
SQL>
Pick the one that suits you best. I believe other members will suggest other options.
I am lucky and i am new to oracle.
I need to retrieve the data from emp table and dept table based on given input deptno and JOB
SELECT
ENAME, E.DEPTNO, JOB , LOC FROM
EMP E , DEPT D where e.deptno=&dno and job ='&JOB' ;
if I enter 10 and clerk
If I write query like this it needs to display only MILLER Record only but the output like as below
MILLER 10 CLERK NEW YORK
MILLER 10 CLERK DALLAS
MILLER 10 CLERK CHICAGO
MILLER 10 CLERK BOSTON
But i need output like
MILLER 10 CLERK NEW YORK
because he belongs to 10th dept and the location is NEW YORK
Please help me on this.
You need to join emp and dept table try
SELECT
ENAME, E.DEPTNO, JOB , LOC FROM
EMP E , DEPT D where e.deptno=&dno
and e.deptno=d.deptno
and job ='&JOB' ;
But i need output like
MILLER 10 CLERK NEW YORK
Then you MUST join both the tables on DEPTNO. You are doing a CARTESIAN join, and therefore it returns you all the 4 rows from DEPT table for one row in EMP table.
You have missed the JOIN condition. So, you need to add this condition:
WHERE e.deptno= d.deptno
Test case:
SQL> SELECT ENAME,
2 E.DEPTNO,
3 JOB ,
4 LOC
5 FROM EMP E ,
6 DEPT D
7 WHERE e.deptno= d.deptno --> Join condition
8 AND E.DEPTNO = &DNO
9 AND job ='&JOB';
Enter value for dno: 10
old 8: AND E.DEPTNO = &DNO
new 8: AND E.DEPTNO = 10
Enter value for job: CLERK
old 9: AND job ='&JOB'
new 9: AND job ='CLERK'
ENAME DEPTNO JOB LOC
---------- ---------- --------- -------------
MILLER 10 CLERK NEW YORK
SQL>