MY_FUN fucntion returns as expected.
SELECT MY_FUN('e1','m1','L1') TEST1 FROM DUAL; --This return value 5 as expected.
TEST1
-----
5
Function parameters are, EQUIP,MODEL and LOT.
It select value in RR column in WC_BASE table
according to EQUIP, MODEL and ITEM1.
And the ITEM1 value is found at table M_IF by LOT.
But,How to modify MY_FUN to return value even ITEM1 value is NULL?
For instance, LOT 'L3' is NULL or LOT4 not exist in M_IF Table.
--How to modify MY_FUN to return 6?
SELECT MY_FUN('e1','m1','L3') TEST2 FROM DUAL;
SELECT MY_FUN('e1','m1','L4') TEST3 FROM DUAL;
Expected result is
TEST2
------
6
TEST3
------
6
[My Table and data]
CREATE TABLE WC_BASE (
EQUIP VARCHAR2(15),
MODEL VARCHAR2(15),
VAL VARCHAR2(15),
ITEM1 VARCHAR2(15),
RR VARCHAR2(15)
);
CREATE TABLE M_IF (
LOT VARCHAR2(15),
ITEM1 VARCHAR2(15)
);
INSERT INTO WC_BASE VALUES('e1','m1','2','c1','5');
INSERT INTO WC_BASE VALUES('e1','m1','1',NULL,'6');
INSERT INTO M_IF VALUES('L1','c1');
INSERT INTO M_IF VALUES('L2','c1');
INSERT INTO M_IF VALUES('L3',NULL);
[My Function]
CREATE OR REPLACE FUNCTION MY_FUN
(
P1 IN VARCHAR2,
P2 IN VARCHAR2,
P3 IN VARCHAR2
)
RETURN NUMBER AS V_VALUE NUMBER;
BEGIN
SELECT (
---
WITH SG AS (SELECT *
FROM WC_BASE
WHERE EQUIP =P1
AND MODEL =P2
AND ITEM1=(SELECT ITEM1 FROM M_IF WHERE LOT = P3) -- How to make an effect of ignoring this condition if the subquery returns null?
)
SELECT (x1) ANSWER
FROM ( SELECT
NVL(TO_NUMBER(RR),0) AS x1
FROM SG
WHERE VAL IN (SELECT TO_CHAR(MAX(TO_NUMBER(VAL))) FROM SG )
)
---
)
INTO V_VALUE
FROM DUAL ;
RETURN V_VALUE;
END MY_FUN;
/
You can change the WITH clause query using OUTER JOIN.
SELECT W.*
FROM WC_BASE W
LEFT JOIN M_IF M
ON (W.ITEM1 = M.ITEM1)
WHERE W.EQUIP =P1
AND W.MODEL =P2
AND M.LOT = P3
Cheers!!
Related
Create a database that contains four tables department, employee,
address and contact info, then Store 5 Records in each table.
Write the PL/SQL Statement for the following:
Store a record into employee, address and contact using trigger.
Retrieve departments and their employees using package
..........................
this is my code , what am i doing wrong ?
-- Question 2 :
-- Create Tables :
CREATE TABLE address (
code int primary key,
city varchar2(30),
street varchar2(30)
);
create table Department (
DepId int primary key ,
Dep_Name varchar2(30) ,
Dep_adress varchar(30));
create table Employee (
Emp_Id int primary key ,
firstName varchar2(30),
lastName varchar2(30),
salary int,
Dep_Id int references Department (DepId),
AdCode int references address (code));
CREATE TABLE contact_info (
email varchar2(30) primary key ,
phone int ,
EmpId int references Employee (Emp_Id));
-- insert :
insert into Department values (1,'IT','Amman');
insert into Department values (2,'CS','Jerash');
insert into Department values (3,'accounting','Amman');
insert into Department values (4,'managment','Amman');
insert into Department values (5,'employment','Amman');
insert into address values (50,'Amman','AAA');
insert into address values (60,'Amman','AAB');
insert into address values (70,'Amman','AAC');
insert into address values (80,'Jerash','AAD');
insert into address values (90,'Irbid','AAE');
insert into Employee (Emp_Id,firstName,lastName,salary,Dep_Id,AdCode) values (1,'john' , 'samo' , 1000 , (select DepId from Department where Dep_Name = 'IT'),(select code from address where street = 'AAA'));
insert into Employee (Emp_Id,firstName,lastName,salary,Dep_Id,AdCode) values (2,'mark' , 'wol' , 2000 , (select DepId from Department where Dep_Name = 'IT'),(select code from address where street = 'AAB'));
insert into Employee (Emp_Id,firstName,lastName,salary,Dep_Id,AdCode) values (3,'ahmad' , 'moh' , 1100 , (select DepId from Department where Dep_Name = 'IT'),(select code from address where street = 'AAC'));
insert into Employee (Emp_Id,firstName,lastName,salary,Dep_Id,AdCode) values (4,'maher' , 'imk' , 1700 , (select DepId from Department where Dep_Name = 'CS'),(select code from address where street = 'AAD'));
insert into Employee (Emp_Id,firstName,lastName,salary,Dep_Id,AdCode) values (5,'ali' , 'geh' , 1200 , (select DepId from Department where Dep_Name = 'CS'),(select code from address where street = 'AAE'));
insert into contact_info values ('john#gmail.com',0785602200, (select Emp_Id from Employee where salary = 1000));
insert into contact_info values ('mark#gmail.com',0785602201, (select Emp_Id from Employee where salary = 2000));
insert into contact_info values ('ahmad#gmail.com',0785602202, (select Emp_Id from Employee where salary = 1100));
insert into contact_info values ('maher#gmail.com',0785602203, (select Emp_Id from Employee where salary = 1700));
insert into contact_info values ('ali#gmail.com',0785602204, (select Emp_Id from Employee where salary = 1200));
-- trigger :
CREATE OR REPLACE TRIGGER add_rec
AFTER INSERT
ON Department
FOR EACH ROW
DECLARE
Empl_id NUMBER;
BEGIN
INSERT INTO address(code,city,street)
VALUES(:NEW.code, :NEW.city, :NEW.street)
INSERT INTO contact_info(email, phone, EmpId)
VALUES(:NEW.email, :NEW.phone, :NEW.EmpId)
INSERT INTO Employee(Emp_Id,firstName,lastName,salary,Dep_Id,AdCode)
VALUES(:NEW.Emp_Id, :NEW.firstName, :NEW.lastName, :NEW.salary, :NEW.lastName, :NEW.Dep_Id, :NEW.AdCode)
END;
-- Package :
set serveroutput on;
CREATE OR REPLACE PACKAGE emp_dept AS
TYPE EmpDept IS RECORD (employee_id number , last_name varchar2(25) , department_id number);
CURSOR dept_employees RETURN EmpDept;
PROCEDURE department_employee;
END emp_dept;
/
CREATE OR REPLACE PACKAGE BODY emp_dept AS
CURSOR dept_employees RETURN EmpDept is (select employee_id , last_name , d.department_id from Employee e join Department d on e.department_id = d.department_id);
rec EmpDept;
PROCEDURE department_employee
is
begin
open dept_employees;
loop
fetch dept_employees into rec;
exit when dept_employees%notfound;
dbms_output.put_line(rpad(rec.employee_id,5,' ') ||rpad(rec.last_name,12,' ') || rec.department_id);
end loop;
end;
END emp_dept;
/
execute EMP_DEPT.DEPARTMENT_EMPLOYEE;
As of package, when you fix errors (wrong column names), it compiles and returns result:
SQL> CREATE OR REPLACE PACKAGE emp_dept AS
2 TYPE empdept IS RECORD (
3 employee_id NUMBER,
4 last_name VARCHAR2(25),
5 department_id NUMBER
6 );
7 CURSOR dept_employees RETURN empdept;
8 PROCEDURE department_employee;
9
10 END emp_dept;
11 /
Package created.
SQL> CREATE OR REPLACE PACKAGE BODY emp_dept AS
2
3 CURSOR dept_employees RETURN empdept IS
4 ( SELECT
5 emp_id,
6 lastname,
7 d.depid
8 FROM
9 employee e
10 JOIN department d ON e.dep_id = d.depid
11 );
12
13 rec empdept;
14
15 PROCEDURE department_employee IS
16 BEGIN
17 OPEN dept_employees;
18 LOOP
19 FETCH dept_employees INTO rec;
20 EXIT WHEN dept_employees%notfound;
21 dbms_output.put_line(rpad(rec.employee_id, 5, ' ')
22 || rpad(rec.last_name, 12, ' ')
23 || rec.department_id);
24
25 END LOOP;
26
27 END;
28
29 END emp_dept;
30 /
Package body created.
Testing:
SQL> EXECUTE emp_dept.department_employee;
1 samo 1
2 wol 1
3 moh 1
4 imk 2
5 geh 2
PL/SQL procedure successfully completed.
SQL>
As of trigger: that question/requirement doesn't make any sense. How would you enter rows into all those tables, based on 3 columns you enter into the department table? You just don't have any values to insert ... From my point of view, either you misinterpreted the problem, or it can't be done as you described it.
I want to add at most three optional parameters to my Oracle function named TEST.
Returned value should be 2.
How to modify my function to make these queries work in a simplest way?
SELECT TEST('eq1','md1') TEST0 FROM DUAL; -- Shows 2 correctly
--How to make these queries also work?
SELECT TEST('eq1','md1','c1') TEST1 FROM DUAL;
SELECT TEST('eq1','md1','c1','d1') TEST2 FROM DUAL;
SELECT TEST('eq1','md1','c1','d1','e1') TEST3 FROM DUAL;
Table and Function are as below.
Table as below
CREATE TABLE T5 (
COL1 VARCHAR2(10),
COL2 VARCHAR2(10),
COL3 VARCHAR2(10),
COL4 VARCHAR2(10),
COL5 VARCHAR2(10),
VAL VARCHAR2(10)
);
INSERT INTO T5 VALUES ('eq1','md1','c1','d1','e1','2');
INSERT INTO T5 VALUES ('eq2','md2','c2','d2','e2','5');
INSERT INTO T5 VALUES ('eq3','md3','c3','d3','e3','3');
My funtion is,
CREATE OR REPLACE FUNCTION TEST
(p1 IN VARCHAR2,
p2 IN VARCHAR2
--How to add optional parameter p3?
--How to add optional parameter p4?
--How to add optional parameter p5?
)
RETURN NUMBER AS V_VALUE VARCHAR2(10);
BEGIN
SELECT(
SELECT VAL FROM T5
WHERE COL1 = p1
AND COL2 = p2
--How to add constraint COL3=p3?
--How to add constraint COL4=p4?
--How to add constraint COL5=p5?
)
INTO V_VALUE
FROM DUAL;
RETURN V_VALUE;
END;
/
You need to define the default value and that's it.
Your function code should look like as follows:
CREATE OR REPLACE FUNCTION TEST (
P1 IN VARCHAR2,
P2 IN VARCHAR2,
P3 IN VARCHAR2 DEFAULT NULL,
P4 IN VARCHAR2 DEFAULT NULL,
P5 IN VARCHAR2 DEFAULT NULL
) RETURN NUMBER AS
V_VALUE VARCHAR2(10);
BEGIN
SELECT
(
SELECT
VAL
FROM
T5
WHERE
COL1 = P1
AND COL2 = P2
AND COL3 = COALESCE(P3, COL3)
AND COL4 = COALESCE(P4, COL4)
AND COL5 = COALESCE(P5, COL5)
)
INTO V_VALUE
FROM
DUAL;
RETURN V_VALUE;
END TEST;
/
Now, all the queries will run:
SELECT TEST('eq1','md1') TEST0 FROM DUAL;
SELECT TEST('eq1','md1','c1') TEST1 FROM DUAL;
SELECT TEST('eq1','md1','c1','d1') TEST2 FROM DUAL;
SELECT TEST('eq1','md1','c1','d1','e1') TEST3 FROM DUAL;
But, Please make sure that order of the passed parameter in the function is not broken.
You can not pass the P5 without passing P4 parameter value except the parameter names are used while calling the function.
Cheers!!
I have requirement where i need to append data to already populated object type. Data to be appended, depends on data which is already populated in object type. Can anyone please help me with this.
I tried below approach which is working fine. But I want to know if there is better way of doing it.
Step 1 : Declare and populate object type 1
Step 2 : Declare another object type 2 and Populate it using object type 1
Step 3 : Declare one more object type 3 for final result-set and populate using combine data of object type 1 and object type 2
Also i need to assign uniq id to each record populated (for which I am using rownum pseudo column )
Below is code that i tried which is working fine. Please note that, in actual requirement, i have many attributes in object type and many filters and joins while populating object type. Below is just simplified code to know the solution.
-- table EMPLOYEE
CREATE TABLE EMPLOYEE
(
ENAME VARCHAR2(128) ,
EADDRESS VARCHAR2(200) ,
ESTATUS VARCHAR2(11) ,
PARENT_NAME VARCHAR2(128)
);
-- Object
CREATE OR REPLACE TYPE OBJ_USER_ACTIVITIES AS OBJECT
(
UNIQ_ID NUMBER(9) ,
EMPNAME VARCHAR2(128) ,
ADDRESS VARCHAR2(200) ,
STATUS VARCHAR2(11) ,
PARENT_NAME VARCHAR2(128)
);
-- Type
CREATE OR REPLACE TYPE TAB_USER_ACTIVITIES IS TABLE OF OBJ_USER_ACTIVITIES;
-- Procedure
CREATE OR REPLACE PROCEDURE Test_Tickets
IS
TEMP_USER_ACTIVITIES_1 TAB_USER_ACTIVITIES := TAB_USER_ACTIVITIES();
TEMP_USER_ACTIVITIES_2 TAB_USER_ACTIVITIES := TAB_USER_ACTIVITIES();
TEMP_USER_ACTIVITIES_FINAL TAB_USER_ACTIVITIES := TAB_USER_ACTIVITIES();
i integer;
BEGIN
-- First resultset
SELECT OBJ_USER_ACTIVITIES
(ROWNUM, EMPNAME, ADDRESS, STATUS, PARENT_NAME)
BULK COLLECT INTO TEMP_USER_ACTIVITIES_1
FROM
(
SELECT ENAME AS EMPNAME, EADDRESS AS ADDRESS, ESTATUS AS STATUS, PARENT_NAME
FROM EMPLOYEE
--WHERE SOME FILTER
);
i := TEMP_USER_ACTIVITIES_1.COUNT;
-- Build second resultset depending on valus of first resultset
SELECT OBJ_USER_ACTIVITIES
( i + ROWNUM, EMPNAME, ADDRESS, STATUS, PARENT_NAME )
BULK COLLECT INTO TEMP_USER_ACTIVITIES_2
FROM
(
SELECT ENAME AS EMPNAME, EADDRESS AS ADDRESS, ESTATUS AS STATUS, PARENT_NAME
FROM EMPLOYEE
WHERE ENAME IN ( SELECT PARENT_NAME FROM TABLE(TEMP_USER_ACTIVITIES_1) WHERE PARENT_NAME IS NOT NULL )
);
-- FINAL resultset combining above two resulset
SELECT OBJ_USER_ACTIVITIES
( UNIQ_ID, EMPNAME, ADDRESS, STATUS, PARENT_NAME )
BULK COLLECT INTO TEMP_USER_ACTIVITIES_FINAL
FROM
(
SELECT UNIQ_ID, EMPNAME, ADDRESS, STATUS, PARENT_NAME
FROM TABLE(TEMP_USER_ACTIVITIES_1)
UNION
SELECT UNIQ_ID, EMPNAME, ADDRESS, STATUS, PARENT_NAME
FROM TABLE(TEMP_USER_ACTIVITIES_2)
);
END;
There is a great set of nested table operators available to you for this. HEre is an example (with some of the other operators commented out just for completeness)
SQL> create or replace type MY_OBJ as object ( x int, y int );
2 /
Type created.
SQL>
SQL> create or replace type MY_OBJ_LIST as table of my_obj
2 /
Type created.
SQL>
SQL> set serverout on
SQL> declare
2 t1 my_obj_list :=
3 my_obj_list(
4 my_obj(1,2),
5 my_obj(3,4),
6 my_obj(5,6));
7
8 t2 my_obj_list :=
9 my_obj_list(
10 my_obj(7,8),
11 my_obj(9,10),
12 my_obj(11,12));
13
14 t3 my_obj_list := my_obj_list();
15 begin
16 t3 := t1 MULTISET UNION t2;
17
18 dbms_output.put_line('I now have '||t3.count||' elements');
19
20 -- t3 := t1 multiset union t2;
21 -- t3 := t1 multiset union distinct t2;
22 -- t3 := t1 multiset intersect t2;
23 -- t3 := t1 multiset intersect distinct t2;
24 -- t3 := set(t2);
25 -- t3 := t1 multiset except t2;
26 -- t3 := t1 multiset except distinct t2;
27
28 end;
29 /
I now have 6 elements
PL/SQL procedure successfully completed.
I am using Oracle and I want to define a store procedure as below, basically it will check whether the passed in p_id is null, if null then generate an id using sequence for table_1, otherwise use the p_id passed in.
tbl_ids_type is a nest table type I defined, which contains numeric ids.
what I want to do is in the LOOP part, before inserting into table_2, I want to query table_2 as select name1, name2 from table_2 where s_id = p_id_list(i), that's because the record with that specific s_id may already exist in the table and I want to re-use the name1 and name2 values.
How can I do that?
procedure save
(
p_id number default null,
p_name varchar2 default null,
p_id_list tbl_ids_type default null,
p_user_id number default null
)
is
tmp_id numeric;
begin
if p_id is null then
tmp_id := seq_1.nextval;
insert into table_1 (
id,
name,
original_id,
user_id,
)
values(
tmp_id,
p_name,
-1,
p_user_id,
for i in 1 .. p_id_list.COUNT
LOOP
insert into table_2(
s_id,
id,
name1,
name2,
user_id
)
values (p_id_list(i), tmp_id, 'test_name1', 'test_name2', p_user_id);
END LOOP;
else
delete from table_1 where id = p_id and user_id = p_user_id;
delete from table_2 where id = p_id and user_id = p_user_id;
insert into table_1 (
id,
name,
original_id,
user_id,
)
values(
p_id,
p_name,
'-1',
p_user_id,
for i in 1 .. p_id_list.COUNT
LOOP
insert into table_2(
s_id,
id,
name1,
name2,
user_id
)
values (p_id_list(i), p_id, 'test_name1', 'test_name2', p_user_id);
END LOOP;
end if;
end save_report;
In your LOOP statement, just run that query and if you find values, store them in a variable. So you would add something like
BEGIN
select name1, name2
into l_name_1, l_name_2
from table_2
where s_id = p_id_list(i);
EXCEPTION WHEN NO_DATA_FOUND
THEN
l_name_1 := 'Some Default';
l_name_2 := 'or maybe Null';
END;
Then you would just change your insert statement to
insert into table_2(
s_id,
id,
name1,
name2,
user_id
)
values (p_id_list(i), tmp_id, l_name_1, l_name_2, p_user_id);
You may also want to add a handler for TOO_MANY_ROWS in that anonymous block.
Try this. You're looking for INTO keyword
l_name1 VARCHAR := NULL
l_name2 VARCHAR := NULL
for i in 1 .. p_id_list.COUNT
LOOP
BEGIN
select name1, name2 INTO l_name1, l_name2 from table_2 where s_id = p_id_list(i)
EXCEPTION
WHEN_NO_DATA_FOUND
//Set l_name1 and l_name2 to what you want to
END
insert into table_2(
s_id,
id,
name1,
name2,
user_id
) values (p_id_list(i), p_id, 'test_name1', 'test_name2', p_user_id);
Please let me know in case you think i am missing something.
I have an oracle function that has a parameter which defines in which column the value should be inserted, e.g.
function something(p_value, p_nr)
is
...
begin
if p_nr = 1 then
insert into A (column1) (p_value);
else if p_nr = 2 then
insert into A (column2) (p_value);
...
end if;
I have a couple of values to enter in the table and only this value should be inserted dynamically. Is there an easier way to do this?
If your table structure defines default values for columns, you might also consider conditional insert:
insert all
when :p_nr = 1 then into A( col1 ) values( p_value )
when :p_nr = 2 then into A( col2 ) values( p_value )
when :p_nr = 3 then into A( col3 ) values( p_value )
select :p_value as p_value from dual
;
The advantage is that this query honors default values, look at an example:
create table A(
col1 varchar2( 10 ) default 'default 1',
col2 varchar2( 10 ) default 'default 2',
col3 varchar2( 10 ) default 'default 3'
);
variable p_nr number
variable p_value varchar2( 100 )
exec :p_nr:=2
exec :p_value:='value'
insert into A (col1, col2, col3)
values (case when :p_nr = 1 then :p_value end,
case when :p_nr = 2 then :p_value end,
case when :p_nr = 3 then :p_value end);
select * from A;
COL1 COL2 COL3
---------- ---------- ----------
value
and:
rollback;
insert all
when :p_nr = 1 then into A( col1 ) values( p_value )
when :p_nr = 2 then into A( col2 ) values( p_value )
when :p_nr = 3 then into A( col3 ) values( p_value )
select :p_value as p_value from dual
;
select * from A;
COL1 COL2 COL3
---------- ---------- ----------
default 1 value default 3
You could do:
insert into A (column1, column2)
values (case when p_nr = 1 then p_value end,
case when p_nr = 2 then p_value end);
That would put the value in one of the two columns, and null in the other; which way round depends on the flag value. (I've omitted the implied else null from both cases, but the intent might be clearer with it in).
Since that's now plain SQL it might not even need to be wrapped in a function (or procedure), depending what else you're doing.