Oracle-Using optional prameters in function? - oracle

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!!

Related

Oracle-How to making an effect of ignoring condition

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!!

If statement inside create table query -Oracle-

I would like to create table which asks user input first. Then based on the input, it select which columns are added.
for example, if the response is 'N', then table is created including columns col1, col2, col3.
If the response is 'Y', table is created including columns col1, col2, col3, col4, col5.
Is this possible?
If yes, please provide me simple and primitive query so that I can apply it to my case.
Thanks,
Using SQL*Plus it's simple:
ACCEPT table_option -
PROMPT 'Create more columns? '
SET TERM OFF
COLUMN extra_columns NEW_VALUE extra_columns
SELECT
CASE '&table_option'
WHEN 'Y' THEN ', C4 NUMBER, C5 VARCHAR2(255), C6 DATE'
END extra_columns FROM DUAL;
CREATE TABLE tmp (
C1 NUMBER,
C2 VARCHAR2(255),
C3 DATE &extra_columns
);
SET TERM ON
You can store the script as a file and invoke it from SQL*Plus using #filename.
CREATE OR REPLACE FUNCTION tmp_custom_DDL( p_input VARCHAR2 IN, p_resp CHAR IN OUT) RETURN CHAR
AS
v_str VARCHAR2(4000);
IF p_resp = 'Y' THEN
v_str := 'col1 varchar2(10), col2 varchar2(10), col3 varchar2(10)';
ELSE v_str := 'col1 varchar2(10), col2 varchar2(10), col3 varchar2(10), col4 varchar2(10), col4 varchar2(10) ' ;
EXECUTE IMMEDIATE v_comm_1 || v_str || v_comm2;
--v_comm_1 is the first half of create table command till the specified cols
--v_comm_2 is the rest of the create table command
RETURN p_resp;
END;
this is only a quick draft, fix the few lexical bug and the missing definitions :) (this is the first step)

Oracle - Cannot update table record using bind variable

This query returns 1 row:
SELECT col1, col2 FROM table1 WHERE col1 = :column1;
But this updates 0 rows:
UPDATE table1 SET col2 = :column2 WHERE col1 = :column1;
COMMIT;
I added this constraint to set col1 as primary key, but it didn't fix it.
ALTER TABLE table1 ADD CONSTRAINT col1_pk PRIMARY KEY (col1);
I am trying this from SQL Developer, any idea why it does not update the row?
EDIT:
col1 is VARCHAR2(32 BYTE) NOT NULL
col2 is CLOB NOT NULL
EDIT 2: Test Case, set :var1 to 0011223344556677 in the select and update sentences.
CREATE TABLE MY_TABLE
( COL1 VARCHAR2(32 BYTE) NOT NULL ENABLE,
COL2 CLOB,
CONSTRAINT "MY_TABLE_PK" PRIMARY KEY ("COL1")
)
INSERT INTO MY_TABLE (COL1, COL2) VALUES ('0011223344556677', '1434407992143440799214344079921434407992');
SELECT * FROM MY_TABLE WHERE COL1 = :var1;
UPDATE MY_TABLE SET COL2 = 'test' WHERE COL1 = :var1;
COMMIT;
TL;DR - Make sure the value being stored in the bind variable is parsed as a character string not a number.
I've run this in SQL Developer (Version 4.0.3.16):
CREATE TABLE MY_TABLE
( COL1 VARCHAR2(32 BYTE) NOT NULL ENABLE,
COL2 CLOB,
CONSTRAINT "MY_TABLE_PK" PRIMARY KEY ("COL1")
);
/
INSERT INTO MY_TABLE (COL1, COL2) VALUES ('0011223344556677', '1434407992143440799214344079921434407992');
/
VARIABLE var1 VARCHAR2(32);
/
BEGIN
:var1 := '0011223344556677';
END;
/
SELECT * FROM MY_TABLE WHERE COL1 = :var1;
/
UPDATE MY_TABLE SET COL2 = 'test' WHERE COL1 = :var1;
/
COMMIT;
/
SELECT * FROM MY_TABLE;
/
And it runs fine:
table MY_TABLE created.
1 rows inserted.
anonymous block completed
COL1 COL2
-------------------------------- --------------------------------------------------------------------------------
0011223344556677 1434407992143440799214344079921434407992
1 rows updated.
committed.
COL1 COL2
-------------------------------- --------------------------------------------------------------------------------
0011223344556677 test
If you change the variable assignment to (remove quotes):
BEGIN
:var1 := 0011223344556677;
END;
Then the value is parsed as a number and the leading zeros are ignored and the output is:
table MY_TABLE created.
1 rows inserted.
anonymous block completed
no rows selected
0 rows updated.
committed.
COL1 COL2
-------------------------------- --------------------------------------------------------------------------------
0011223344556677 1434407992143440799214344079921434407992

Setting default value in Oracle Object Type Constructor Function

I want to set default values in Oracle object type, but it requires all attributes needs to be passed in constructor function for that.
Is there anyway, so that I can pass only required attributes in constructor function for which default value is required.
Please see the following details
SQL> CREATE TYPE TYPE_SUB AS OBJECT(
2 COL1 NUMBER,
3 COL2 VARCHAR2(100)
4 )
5 NOT FINAL
6 /
Type created.
SQL> CREATE OR REPLACE TYPE TYPE_MAIN
2 UNDER TYPE_SUB
3 (
4 COL3 varchar2(10),
5 COL4 VARCHAR2(10),
6 CONSTRUCTOR FUNCTION TYPE_MAIN(COL1 NUMBER, COL2 VARCHAR2, COL3 varchar2, COL4 VARCHAR2) RETURN SELF AS RESULT)
7 NOT FINAL
8 /
Type created.
SQL> CREATE OR REPLACE TYPE BODY TYPE_MAIN IS
2 CONSTRUCTOR FUNCTION TYPE_MAIN (COL1 NUMBER, COL2 VARCHAR2, COL3 varchar2, COL4 VARCHAR2) RETURN SELF AS RESULT IS
3 BEGIN
4 SELF.COL1 := nvl(COL1,123);
5 SELF.COL2 := nvl(COL2,'NA');
6 SELF.COL3 := nvl(COL3,'NA');
7 SELF.COL4 := nvl(COL4,NULL);
8 RETURN;
9 end;
10 END;
11 /
Type body created.
SQL> CREATE TABLE TAB_MAIN (
2 PKEY NUMBER,
3 COLTEST VARCHAR2(100),
4 COLNEW TYPE_MAIN)
5 /
Table created.
SQL> INSERT INTO TAB_MAIN(PKEY) VALUES(1)
2 /
1 row created.
SQL> INSERT INTO TAB_MAIN(PKEY,COLTEST,COLNEW) VALUES(1,'TESTCOL',TYPE_MAIN('1','2',NULL,NULL))
2 /
1 row created.
SQL> INSERT INTO TAB_MAIN(PKEY,COLTEST,COLNEW) VALUES(1,'TESTCOL2',TYPE_MAIN('1',NULL,NULL,NULL))
2 /
1 row created.
SQL> SELECT * FROM TAB_MAIN
2 /
PKEY COLTEST COLNEW(COL1, COL2, COL3, COL4)
---------- ---------- ----------------------------------------
1
1 TESTCOL TYPE_MAIN(1, '2', 'NA', NULL)
1 TESTCOL2 TYPE_MAIN(1, 'NA', 'NA', NULL)
Now, in above example if I will pass only Col3 and Col4 attribute in constructor function for default value, then it didn't work. Please see the following example.
SQL> CREATE TYPE TYPE_SUB AS OBJECT(
2 COL1 NUMBER,
3 COL2 VARCHAR2(100)
4 )
5 NOT FINAL
6 /
Type created.
SQL> CREATE OR REPLACE TYPE TYPE_MAIN
2 UNDER TYPE_SUB
3 (
4 COL3 varchar2(10),
5 COL4 VARCHAR2(10),
6 CONSTRUCTOR FUNCTION TYPE_MAIN(COL3 varchar2, COL4 VARCHAR2) RETURN SELF AS RESULT)
7 NOT FINAL
8 /
Type created.
SQL> CREATE OR REPLACE TYPE BODY TYPE_MAIN IS
2 CONSTRUCTOR FUNCTION TYPE_MAIN (COL3 varchar2, COL4 VARCHAR2) RETURN SELF AS RESULT IS
3 BEGIN
4 SELF.COL3 := nvl(COL3,'NA');
5 SELF.COL4 := nvl(COL4,NULL);
6 RETURN;
7 end;
8 END;
9 /
Type body created.
SQL> CREATE TABLE TAB_MAIN (
2 PKEY NUMBER,
3 COLTEST VARCHAR2(100),
4 COLNEW TYPE_MAIN)
5 /
Table created.
SQL> INSERT INTO TAB_MAIN(PKEY) VALUES(1)
2 /
1 row created.
SQL> INSERT INTO TAB_MAIN(PKEY,COLTEST,COLNEW) VALUES(1,'TESTCOL',TYPE_MAIN('1','2',NULL,NULL))
2 /
1 row created.
SQL> INSERT INTO TAB_MAIN(PKEY,COLTEST,COLNEW) VALUES(1,'TESTCOL2',TYPE_MAIN('1',NULL,NULL,NULL))
2 /
1 row created.
SQL> SELECT * FROM TAB_MAIN
2 /
PKEY COLTEST COLNEW(COL1, COL2, COL3, COL4)
---------- ---------- ----------------------------------------
1
1 TESTCOL TYPE_MAIN(1, '2', NULL, NULL)
1 TESTCOL2 TYPE_MAIN(1, NULL, NULL, NULL)
In your second code block, you aren't calling the constructor that only has two arguments. Passing a null argument doesn't mean you use the other constructor, you're calling the (default) constructor with four arguments, two of which just happen to be intentionally null. You're effectively doing:
TYPE_MAIN(col1 => '1', col2 => NULL, col3 => NULL, col4 => NULL)
not
TYPE_MAIN(col3 => '1', col4 => NULL)
So this works:
INSERT INTO TAB_MAIN(PKEY,COLTEST,COLNEW) VALUES(1,'TESTCOL2',TYPE_MAIN('3','4'))
/
...
PKEY COLTEST COLNEW
---------- --------------- --------------------------------------------------
1
1 TESTCOL TYPE_MAIN(1,'2',NULL,NULL)
1 TESTCOL2 TYPE_MAIN(1,NULL,NULL,NULL)
1 TESTCOL2 TYPE_MAIN(NULL,NULL,'3','4')
To get the defaults to work as I think you intend in your first code block, set them in the constructor parameters, not in the body of the constructor:
CREATE OR REPLACE TYPE TYPE_MAIN
UNDER TYPE_SUB
(
COL3 varchar2(10),
COL4 VARCHAR2(10),
CONSTRUCTOR FUNCTION TYPE_MAIN(COL1 number default 123,
COL2 VARCHAR2 default 'NA',
COL3 varchar2 default 'NA',
COL4 VARCHAR2 default null) RETURN SELF AS RESULT)
NOT FINAL
/
CREATE OR REPLACE TYPE BODY TYPE_MAIN IS
CONSTRUCTOR FUNCTION TYPE_MAIN (COL1 number default 123,
COL2 VARCHAR2 default 'NA',
COL3 varchar2 default 'NA',
COL4 VARCHAR2 default null) RETURN SELF AS RESULT IS
BEGIN
SELF.COL1 := COL1;
SELF.COL2 := COL2;
SELF.COL3 := COL3;
SELF.COL4 := COL4;
RETURN;
end;
END;
/
Then when only passing one of the arguments (or any time you aren't passing them all, or the first few that you want to override in order starting from col1) you need to name it, rather than passing null for the others, as that would only override the defaults.
INSERT INTO TAB_MAIN(PKEY) VALUES(1)
/
INSERT INTO TAB_MAIN(PKEY,COLTEST,COLNEW)
VALUES(1,'TESTCOL',TYPE_MAIN(1,'2'))
/
INSERT INTO TAB_MAIN(PKEY,COLTEST,COLNEW)
VALUES(1,'TESTCOL2',TYPE_MAIN(1))
/
INSERT INTO TAB_MAIN(PKEY,COLTEST,COLNEW)
VALUES(1,'TESTCOL3',TYPE_MAIN(col3 => '3'))
/
INSERT INTO TAB_MAIN(PKEY,COLTEST,COLNEW)
VALUES(1,'TESTCOL4',TYPE_MAIN(col4 => '4'))
/
PKEY COLTEST COLNEW
---------- --------------- --------------------------------------------------
1
1 TESTCOL TYPE_MAIN(1,'2','NA',NULL)
1 TESTCOL2 TYPE_MAIN(1,'NA','NA',NULL)
1 TESTCOL3 TYPE_MAIN(123,'NA','3',NULL)
1 TESTCOL4 TYPE_MAIN(123,'NA','NA','4')
To pass both col3 and col4 you'll still need to name the arguments, otherwise it will assume you're starting from col1:
INSERT INTO TAB_MAIN(PKEY,COLTEST,COLNEW)
VALUES(1,'TESTCOL5',TYPE_MAIN(col3 => '3', col4 => '4'))
/
PKEY COLTEST COLNEW
---------- --------------- --------------------------------------------------
1
1 TESTCOL TYPE_MAIN(1,'2','NA',NULL)
1 TESTCOL2 TYPE_MAIN(1,'NA','NA',NULL)
1 TESTCOL3 TYPE_MAIN(123,'NA','3',NULL)
1 TESTCOL4 TYPE_MAIN(123,'NA','NA','4')
1 TESTCOL5 TYPE_MAIN(123,'NA','3','4')

oracle sql dynamic insert statement

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.

Resources