Function having an in parameter and returning a object type - oracle

How can I pass number as in parameter and return a object type in a function
create type my_details as
object(v_ename varchar2(20),v_sal number(10));
create or replace function f_emp(v_empno in number)
return my_details
as
v_det my_details;
begin
select ename,sal
into v_det.v_ename,v_det.v_sal
from emp
where empno=v_empno;
return v_det;
end;
When I try to call the function, I get an error
declare
v_type my_details;
begin
v_type:=f_emp(7839);
end;
/
The error stack
declare
*
ERROR at line 1:
ORA-06530: Reference to uninitialized composite
ORA-06512: at "SCOTT.F_EMP", line 6
ORA-06512: at line 4
Can any one help me pointing out where I have made mistake and how can I improve this?

Your function would either need to initialize the object before referencing it
create or replace function f_emp(v_empno in number)
return my_details
as
v_det my_details := new my_details(null, null);
begin
select ename,sal
into v_det.v_ename,v_det.v_sal
from emp
where empno=v_empno;
return v_det;
end;
or your could call the constructor as part of the select
create or replace function f_emp(v_empno in number)
return my_details
as
v_det my_details;
begin
select my_details(ename,sal)
into v_det
from emp
where empno=v_empno;
return v_det;
end;
Putting the constructor in the select statement would be the approach I would generally suggest.

Related

Pipelining Between PL/SQL Table Functions

I have a package with 2 pipelined functions. When I'm trying to call one function with another function as it's argument I'm getting "ORA-06553: PLS-306: wrong number or types of arguments in call" error.
Here is the package:
create or replace NONEDITIONABLE TYPE RESULTING_RECORD_RT as object
(
CALENDAR NVARCHAR2(1024),
PRODUCT NVARCHAR2(1024),
MEASURE NVARCHAR2(1024),
VALUE NUMBER
);
/
create or replace NONEDITIONABLE TYPE RESULTING_COLS_RT IS TABLE OF RESULTING_RECORD_RT;
/
create or replace package pipe_pkg as
function pipe_func_emp return RESULTING_COLS_RT PIPELINED;
function pipe_func_emp2(input_Set IN resulting_cols_rt) return RESULTING_COLS_RT PIPELINED;
end;
/
create or replace package body pipe_pkg as
function pipe_func_emp return RESULTING_COLS_RT
PIPELINED
is
test_tbl resulting_cols_rt:= resulting_cols_rt();
begin
test_tbl.extend;
test_tbl(1):=resulting_record_rt('A','B','C',1);
test_tbl.extend;
test_tbl(2):=resulting_record_rt('A','B','D',2);
PIPE ROW(test_tbl(1));
PIPE ROW(test_tbl(2));
return;
end;
function pipe_func_emp2(input_Set IN resulting_cols_rt) return RESULTING_COLS_RT
PIPELINED
is
v_tmp NVARCHAR2(10240);
l_res SYS_REFCURSOR;
recs resulting_record_rt;
begin
open l_res for select * from table(input_Set);
loop
fetch l_res into recs;
PIPE ROW(recs);
exit when l_res%notfound;
end loop;
close l_res;
return;
end;
end;
/
I'm calling the functions as follows:
select * from TABLE(pipe_pkg.pipe_func_emp2(CURSOR(select * from TABLE(pipe_pkg.pipe_func_emp()))));
And the call throws error:
ORA-06553: PLS-306: wrong number or types of arguments in call to 'PIPE_FUNC_EMP2'
06553. 00000 - "PLS-%s: %s"
What am I doing wrong?
The function pipe_func_emp2 expected RESULTING_COLS_RT as it's argument, but got REF CURSOR. These are incompatible types.
Try following reproducible example of a chaining of the pipelined functions:
create or replace type somerow as object (id int, val varchar2 (8))
/
create or replace type sometab is table of somerow
/
create or replace package pack as
function func1 return sometab pipelined;
function func2 (cur sys_refcursor) return sometab pipelined;
end;
/
create or replace package body pack as
function func1 return sometab pipelined is
tab sometab := sometab (somerow (1,'AAA'), somerow (2,'BBB'));
begin
for i in 1..tab.count loop
pipe row (tab(i));
end loop;
return;
end;
function func2 (cur sys_refcursor) return sometab pipelined is
sr somerow;
begin
loop
fetch cur into sr;
exit when cur%notfound;
pipe row (sr);
end loop;
close cur;
return;
end;
end;
/
The query and it's outcome:
select *
from table (pack.func2 (
cursor (select value (p) from table (pack.func1()) p )))
/
ID VAL
---------- --------
1 AAA
2 BBB

PLSQL Getting expression is of wrong type

I'm a newbee to PLSQL and I'm facing issues while created PLSQL function.It says expression is of wrong type.I need some help.
Here is my function
CREATE OR REPLACE TYPE HOTGROUPTYPE AS OBJECT (
IMEI VARCHAR2(255),
LACCI VARCHAR2(255),
FRAUD_TYPE VARCHAR2(255),
MSISDN VARCHAR2(255)
);
/
CREATE OR REPLACE TYPE HOTGROUPTYPE_tab IS TABLE OF HOTGROUPTYPE;
/
CREATE OR REPLACE FUNCTION get_tab_tf (p_count IN NUMBER, p_days IN NUMBER) RETURN HOTGROUPTYPE_tab
AS
l_tab HOTGROUPTYPE_tab:=HOTGROUPTYPE_tab();
BEGIN
for i in (select IMEI,LACCI,FRAUD_TYPE,MSISDN
from fms_fraud_master_tbl
where request_type='BARRING'
and rownum<2)
loop
l_tab.extend;
l_tab(l_tab.last) := i.IMEI;
end loop;
RETURN l_tab;
END;
/
And I'm getting this error when the execute the function
11/3 PL/SQL: Statement ignored
11/28 PLS-00382: expression is of wrong type
You are not assigning the values to your table type properly. l_tab(<index>) must be assigned the variable of type HOTGROUPTYPE.
You must use this:
l_tab(l_tab.last) := HOTGROUPTYPE(i.IMEI, i.LACCI,i.FRAUD_TYPE,i.MSISDN );
The neatest way to populate a collection from a query is to use bulk collect:
CREATE OR REPLACE FUNCTION get_tab_tf (p_count IN NUMBER, p_days IN NUMBER) RETURN HOTGROUPTYPE_tab
AS
l_tab HOTGROUPTYPE_tab:=HOTGROUPTYPE_tab();
BEGIN
select HOTGROUPTYPE( IMEI,LACCI,FRAUD_TYPE,MSISDN )
bulk collect into l_tab
from fms_fraud_master_tbl
where request_type='BARRING' ;
RETURN l_tab;
END;
/

Error(11,10): PLS-00306: wrong number or types of arguments in call to 'CONSTRUCT'

I am new to plsql i try to run the piece of code but it is giving error and not able to debug
create or replace type final as object ( ename1 varchar2(10), sal1
NUMBER(7,2));--object
create or replace type construct is table of final; /*nested table of
object type */
create or replace function returnmore (empno1 number) /*Function to
return more*/
return construct
AS
vemp construct:=construct();
vename varchar2(10);
vsal1 NUMBER(7,2);
begin
select ENAME,sal into vename,vsal1 from emp where empno=empno1;
vemp.extend;
vemp(1):=construct(vename,vsal1);
return vemp;
end;
But gives me an error
Function SYSTEM.RETURNMORE#loacaDB
Error(11,1): PL/SQL: Statement ignored
Error(11,10): PLS-00306: wrong number or types of arguments in call to 'CONSTRUCT'
I am using oracle10gxe and sqldeveloper4.2
You can prefer using non-preserved keyword such as typ_emp instead of final which's reserved.
SQL> create or replace type typ_emp as object ( ename1 varchar2(10), sal1 number(7,2));
SQL> create or replace type construct is table of typ_emp;
and you can convert your function as below :
create or replace function returnmore( empno1 emp.empno%type )
return construct AS
vemp construct := construct();
vename varchar2(10);
vsal1 number(7, 2);
begin
select ename, sal into vename, vsal1 from emp where empno = empno1;
vemp.extend;
vemp(1) := typ_emp(vename, vsal1);
dbms_output.put_line(vemp(1).ename1);
return vemp;
end;
/
or another way to handle the same operation :
SQL> create or replace function returnmore( empno1 emp.empno%type )
return construct AS
vemp construct := construct();
v_sql varchar2(2000);
begin
v_sql := 'select typ_emp(ename, sal) from emp where empno = :v_empno1';
execute immediate v_sql bulk collect into vemp using empno1;
dbms_output.put_line(vemp(1).ename1);
return vemp;
end;
/
and test by invoking
SQL> set serveroutput on;
SQL> declare
result construct;
begin
result := returnmore( 1 ); -- 1 is just an ordinary presumed value for empno
end;
/ --> this will return the employee name as printed.
P.S. Never ever use SYSTEM user for non-administrative purposes. May be extremely harmful for your database.

Pipelined function with a parameter declare with %ROWTYPE

I'm trying to declare a pipelined table function (t) inside a package that takes an argument declared as <tablename>%ROWTYPE. Declaring that function works and the package compiles without any error.
But I would like to use this function inside a procedure (p1) like shown below.
CREATE OR REPLACE PACKAGE BODY t1
AS
-- private
PROCEDURE p1
IS
l_person persons%ROWTYPE;
BEGIN
FOR l_row IN (SELECT *
FROM TABLE (t (l_person)))
LOOP
NULL;
END LOOP;
END;
-- public
FUNCTION t (p_persons_record persons%ROWTYPE)
RETURN t_a_list
PIPELINED
IS
l_a t_a;
BEGIN
l_a.dummy := 'A';
PIPE ROW (l_a);
END;
END;
This sample code does not makes sense but it demonstrates my problem.
It just doesn't compile but gives the following errors:
[Error] PLS-00382 (10: 38): PLS-00382: expression is of wrong type
[Error] PLS-00306 (10: 35): PLS-00306: wrong number or types of arguments in call to 'T'
[Error] ORA-00904 (10: 35): PL/SQL: ORA-00904: "T1"."T": invalid identifier
Can anyone explain what's wrong and how to fix those errors?
Edit:
The package spec is:
CREATE OR REPLACE PACKAGE t1
AS
TYPE t_a IS RECORD (dummy VARCHAR2 (1));
TYPE t_a_list IS TABLE OF t_a;
FUNCTION t (p_persons_record persons%ROWTYPE)
RETURN t_a_list
PIPELINED;
END;
You cannot use a record type in SQL Scope. So a PL/SQL function with a record parameter derived by rowtype attribute cannot be used as table function in SQL.
The only thing you have to rewrite is to use a SQL object on schema level instead of a PL/SQL record.
-- adapt your columns to your table as necessary
CREATE OR REPLACE TYPE g_persons AS OBJECT (
ID int,
C1 int
);
CREATE OR REPLACE PACKAGE t1
AS
TYPE t_a IS RECORD (dummy VARCHAR2 (1));
TYPE t_a_list IS TABLE OF t_a;
FUNCTION t (p_persons_record g_persons_t)
RETURN t_a_list
PIPELINED;
END;
/
CREATE OR REPLACE PACKAGE BODY t1
AS
-- private
PROCEDURE p1
IS
l_person g_persons_t;
BEGIN
l_person.ID := 1; -- init your record some how
l_person.C1 := 1; -- init your record some how
FOR l_row IN (SELECT *
FROM TABLE (t (l_person)))
LOOP
NULL;
END LOOP;
END;
-- public
FUNCTION t (p_persons_record g_persons_t)
RETURN t_a_list
PIPELINED
IS
l_a t_a;
BEGIN
l_a.dummy := 'A';
PIPE ROW (l_a);
END;
END;
/
I think your PACKAGE specification lacks t's declaration. Have you checked that your PACKAGE specification is something similar to this?:
CREATE OR REPLACE PACKAGE t1 AS
PROCEDURE p1;
FUNCTION t (p_persons_record persons%ROWTYPE) RETURN t_a_list PIPELINED;
END;

How to run Oracle function which returns more than one value

My test function is this
CREATE OR REPLACE FUNCTION MULTI_VAL
(MYNAME OUT EMP2017.ENAME%TYPE)
RETURN NUMBER AS
MYSAL EMP2017.SAL%TYPE;
BEGIN
SELECT SAL, ENAME INTO MYSAL, MYNAME FROM EMP2017 ;
RETURN MYSAL;
END;
/
When I run it like
variable mynm varchar2(20)
SELECT MULTI_VAL(:mynm) FROM dual;
it gives this error
ERROR at line 1:
ORA-06553: PLS-561: character set mismatch on value for parameter 'MYNAME'
The error you get now indicates a datatype mismatch.
However there is a fundamental problem with your code. We cannot use functions which have OUT parameters in SQL. So once you have fixed the datatype issue you will get this error: ORA-06572: Function MULTI_VAL has out arguments.
You can run it like this:
declare
n varchar2(20);
x number;
begin
x := multi_val(n);
end;
/
Generally, functions with OUT parameters are considered bad practice. The syntax allows them, but the usage is hard to understand. It's better to use a procedure with two OUT parameters (because we can only call the program in PL/SQL anyway) or else have the function return a user-defined type.
CREATE TABLE EMP2017(ENAME VARCHAR2(10),SAL NUMBER);
INSERT INTO EMP2017 VALUES ('SMITH',5000);
INSERT INTO EMP2017 VALUES ('JOHNS',1000);
COMMIT;
CREATE TYPE RET_MULT AS OBJECT
(ENAME VARCHAR2(10),SAL NUMBER);
CREATE TYPE T_RET_MULT AS TABLE OF RET_MULT;
CREATE OR REPLACE FUNCTION MULTI_VAL RETURN T_RET_MULT PIPELINED IS
MYSAL RET_MULT;
BEGIN
FOR I IN(SELECT SAL, ENAME FROM EMP2017) LOOP
MYSAL := RET_MULT(I.ENAME,I.SAL);
PIPE ROW(MYSAL);
END LOOP ;
RETURN ;
END;
SELECT * FROM TABLE(MULTI_VAL());
I think this question can be solved without using pipeline functions. Just like this. All pre required data as described #Sedat.Turan except function. Sorry for copy/past.
CREATE TABLE EMP2017(ENAME VARCHAR2(10),SAL NUMBER);
INSERT INTO EMP2017 VALUES ('SMITH',5000);
INSERT INTO EMP2017 VALUES ('JOHNS',1000);
COMMIT;
CREATE TYPE RET_MULT AS OBJECT
(ENAME VARCHAR2(10),SAL NUMBER);
CREATE TYPE T_RET_MULT AS TABLE OF RET_MULT;
create or replace function MULTI_VAL return T_RET_MULT is
RET_SET T_RET_MULT;
begin
select RET_MULT(ENAME, SAL) bulk collect into RET_SET from EMP2017;
return RET_SET;
end;

Resources