How to create oracle view by a function - sql

how to create oracle view by function
1. First create a type 'p_type'
2. Create a table 'p_table' as 'p_type'
3. A function with 'p_table' pipeline
create or replace type p_type as object (
v_name varchar(400),
d_date date,
i_val number
);
create or replace type p_table as table of p_type;
create or replace function get_info return p_table pipelined
is
c number;
begin
c := 1;
/*
A is table and it has only one 'a' attribute
*/
for i in (select * from A) loop
pipe row( p_type(
v_name => SUBSTR(i.A, 1, 10),
d_date => sysdate,
i_val => c
) );
c := c + 1;
end loop;
return;
end;
CREATE VIEW vw_info AS
select * from table(get_info);

Related

How to select only the colums of a table which are the same of another table

info about polymorphic table functions
I'm using a polymorphic function (skip_col_not_in_model ) to remove the columns of a table which are not in another table.
CREATE OR REPLACE PACKAGE pkg_skip_col
AS
FUNCTION skip_col (tab TABLE, col COLUMNS)
RETURN TABLE
PIPELINED ROW POLYMORPHIC USING pkg_skip_col;
FUNCTION describe (tab IN OUT DBMS_TF.TABLE_T, col DBMS_TF.COLUMNS_T)
RETURN DBMS_TF.DESCRIBE_T;
FUNCTION skip_col_not_in_model (tab TABLE, tabk_model TABLE)
RETURN TABLE
PIPELINED ROW POLYMORPHIC USING pkg_skip_col;
FUNCTION describe (tab IN OUT DBMS_TF.TABLE_T,
tab_model IN DBMS_TF.TABLE_T)
RETURN DBMS_TF.DESCRIBE_T;
END;
CREATE OR REPLACE PACKAGE BODY pkg_skip_col
AS
FUNCTION describe (tab IN OUT DBMS_TF.TABLE_T,
tab_model IN DBMS_TF.TABLE_T)
RETURN DBMS_TF.DESCRIBE_T
AS
BEGIN
FOR i IN 1 .. tab.column.COUNT ()
LOOP
FOR j IN 1 .. tab_model.column.COUNT ()
LOOP
tab.column (i).PASS_THROUGH :=
tab.column (i).DESCRIPTION.NAME = tab_model.column (i).DESCRIPTION.NAME ;
EXIT WHEN tab.column (i).PASS_THROUGH;
END LOOP;
END LOOP;
RETURN NULL;
END;
FUNCTION describe (tab IN OUT DBMS_TF.TABLE_T, col DBMS_TF.COLUMNS_T)
RETURN DBMS_TF.DESCRIBE_T
AS
BEGIN
FOR i IN 1 .. tab.column.COUNT ()
LOOP
FOR j IN 1 .. col.COUNT ()
LOOP
tab.column (i).PASS_THROUGH :=
tab.column (i).DESCRIPTION.NAME != col (j);
EXIT WHEN NOT tab.column (i).PASS_THROUGH;
END LOOP;
END LOOP;
RETURN NULL;
END;
END;
/
I can compile the body. But not the spec.
[Error] Compilation (24: 59): PLS-00766: more than one parameter of TABLE type is not allowed
Similary to this query
with a (a1,a2) as (select 1,2 from dual) select * from
pkg_skip_col.skip_col(a,COLUMNS(a1))
a1:1
I would like to do that
with a (a1,a2) as (select 1,2 from dual),
b (a1,a2,a3) as (select 1,2,3 from dual)
select * from pkg_skip_col.skip_col_not_in_model(a,b)
a1:1, a2: 2 (expected resulted only)
The problem comes from the fact that I can't give two table.
to avoid this problem, I can give the table_model as a string, get the column (search in table all_tab_columns ).
But the code is not so easy to understand anymore und doesn't work with common table expression.
Has somebody ideas of improvement?
code
You can do this (from 19.6) using SQL macros. Unlike polymorphic table functions, these allow you to have many dbms_tf.table_t arguments.
SQL macros return the text of a SQL expression which is constructed at parse time. So here you can build the select list similar to the method you've used in the PTF.
For example:
create or replace function skip_col_not_in_model (
query_table dbms_tf.table_t,
ref_table dbms_tf.table_t
)
return clob sql_macro as
select_list clob;
stmt clob;
begin
<<query_cols>>
for i in 1 .. query_table.column.count loop
for j in 1 .. ref_table.column.count loop
if query_table.column(i).description.name = ref_table.column(j).description.name then
select_list :=
select_list
|| query_table.column(i).description.name
|| ',';
continue query_cols;
end if;
end loop;
end loop;
stmt := 'select '
|| rtrim ( select_list, ',' )
|| ' from query_table';
return stmt;
end skip_col_not_in_model;
/
with a (a1,a2) as (
select 1,2 from dual
), b (a1,a2,a3) as (
select 1,2,3 from dual
)
select *
from skip_col_not_in_model ( a, b );
A1 A2
---------- ----------
1 2
You can convert any describe only polymorphic table to a macro.
to avoid this problem, I can give the table_model as a string
In general this doesn't work! As the docs say:
While the constant scalar values are passed as-is to the DESCRIBE
function, all other values are passed as NULLs.
So if you use a bind variable to pass the table name, it's value is null.
In this example, notice that when using :new_col for the string parameter val its null in the describe:
create or replace package ptf_pkg
as
function select_val (tab table, val varchar2)
return table
pipelined row polymorphic using ptf_pkg;
function describe ( tab in out dbms_tf.table_t, val varchar2 )
return dbms_tf.describe_t;
end;
/
create or replace package body ptf_pkg
as
function describe ( tab in out dbms_tf.table_t, val varchar2 )
return dbms_tf.describe_t
as
begin
dbms_tf.trace ( 'val = ' || nvl ( val, 'IT IS NULL' ) );
return null;
end;
end;
/
select * from ptf_pkg.select_val ( dual, 'Y' );
D
-
X
val = Y
var new_col varchar2(30);
exec :new_col := 'NEW_COL';
select * from ptf_pkg.select_val ( dual, :new_col );
D
-
X
val = IT IS NULL

PLSQL - IN clause using variable with multiple values

I am looping a statement and extracting the IDs and putting it into a variable:
declare
l_id NUMBER;
BEGIN
FOR i IN 1..l_row_count
loop
l_id := to_number(apex_json.get_varchar2(p_path => 'rows[%d].id',
p0 => i, p_values => l_values
)
);
end loop:
I am trying to get all the ids and then run a select statement where this list of IDs will be used inside of a where statement. So the full code would look like this:
declare
l_id NUMBER;
l_id_list [SOME_TYPE_NOT_SURE];
BEGIN
FOR i IN 1..l_row_count
loop
l_id := to_number(apex_json.get_varchar2(p_path => 'rows[%d].id',
p0 => i, p_values => l_values
)
);
//somehow add l_id to the l_id_list
end loop:
SELECT * FROM mytable WHERE someid IN (l_id_list);
END;
I haven't been able to get it to work. I am not an expert in PLSQL, but I tried using arrays or trying to concat the l_id_list as a string, but I am unable to get it work. Basically all I am trying to do is create a list of all the IDs, then run a select statement to see if these IDs exist in this other table.
Declare the type globally:
CREATE TYPE number_list IS TABLE OF NUMBER;
Then you can initialise the list and then, in each iteration of the loop, EXTEND the list and assign the value and, finally, use the MEMBER OF operator or IN with a subquery and table collection expression:
DECLARE
l_id_list NUMBER_LIST := NUMBER_LIST();
BEGIN
FOR i IN 1..l_row_count
LOOP
l_id_list.EXTEND;
l_id_list(l_id_list.COUNT) := to_number(
apex_json.get_varchar2(
p_path => 'rows[%d].id',
p0 => i,
p_values => l_values
)
);
END LOOP;
SELECT *
-- BULK COLLECT INTO ...
FROM mytable
WHERE someid MEMBER OF l_id_list;
-- or
SELECT *
-- BULK COLLECT INTO ...
FROM mytable
WHERE someid IN (SELECT COLUMN_VALUE FROM TABLE(l_id_list));
END;
In your case l_id_list's type must be declared globally and as collection-type. Locally defined types cannot be used as collections, so cannot be used inside in-clause.
declare
l_id NUMBER;
l_id_list [SOME_GLOBAL_COLLECTION_TYPE];
BEGIN
FOR i IN 1..l_row_count
loop
l_id := to_number(apex_json.get_varchar2(p_path => 'rows[%d].id',
p0 => i, p_values => l_values
)
);
//somehow add l_id to the l_id_list
end loop:
SELECT * FROM mytable WHERE someid IN (select * from table(l_id_list));
END;

Method Function not getting values from single row (Nested table)

Hi I've asked a question related to this already but have a second question. I commented that I made a nested table of the teams that played rather than separate rows for each team and score.
I want to run the Method for a particular GameId rather than all the rows in the table.. I've included my Game_Type Object this time though I didn't think it was necessary last time.
CREATE TYPE Game_Type AS OBJECT
(GameId NUMBER)
/
CREATE TABLE Game_Table of Game_Type
/
INSERT INTO Game_Table
VALUES (1)
/
INSERT INTO Game_Table
VALUES (2)
/
CREATE TYPE Team_Type AS OBJECT
(TeamPlayed VARCHAR2(30),
TeamScore NUMBER(1))
/
CREATE TYPE TeamsPlayed_Table as TABLE OF Team_Type
/
CREATE OR REPLACE TYPE After_Team AS OBJECT
(GameRef REF Game_Type,
GamePlayed Teamsplayed_Table,
MAP MEMBER FUNCTION team_rating RETURN NUMBER)
/
CREATE TABLE Team_Table of After_Team NESTED TABLE GamePlayed STORE AS
GamePlayed_Nested
/
CREATE OR REPLACE TYPE BODY After_Team
AS
MAP MEMBER FUNCTION team_rating
RETURN NUMBER
IS
avg_score NUMBER;
BEGIN
SELECT AVG(c.TeamScore)
INTO avg_score
FROM Team_Table d, table(d.GamePlayed) c;
RETURN avg_score;
END;
END;
/
INSERT INTO Team_Table
VALUES((SELECT REF(a) FROM Game_Table a WHERE a.gameid = 1),
(TeamsPlayed_Table(Team_Type('Team A', 1), Team_Type('Team B', 3))))
/
INSERT INTO Team_Table
VALUES((SELECT REF(a) FROM Game_Table a WHERE a.gameid = 2),
(TeamsPlayed_Table(Team_Type('Team C', 5), Team_Type('Team D', 9))))
/
Now when I execute my method:
SELECT t.team_rating()
from Team_Table t
where t.GameRef.GameId = 1
It's returning the average for all the values as opposed to just Game 1..
Assuming you want to get the average of the TeamScore in the GamePlayed collection for that team then you can do it in pure PL/SQL (without a context-switch into the SQL scope):
CREATE OR REPLACE TYPE BODY After_Team
AS
MAP MEMBER FUNCTION team_rating
RETURN NUMBER
IS
avg_score NUMBER := 0;
j INTEGER := 0;
BEGIN
FOR i IN 1 .. self.GamePlayed.COUNT LOOP
IF self.GamePlayed(i) IS NOT NULL AND self.GamePlayed(i).TeamScore IS NOT NULL THEN
avg_score := avg_score + self.GamePlayed(i).TeamScore;
j := j + 1;
END IF;
END LOOP;
IF j > 0 THEN
RETURN avg_score / j;
ELSE
RETURN NULL;
END IF;
END;
END;
/
SQLFIDDLE
otherwise, you could use:
CREATE OR REPLACE TYPE BODY After_Team
AS
MAP MEMBER FUNCTION team_rating
RETURN NUMBER
IS
avg_score NUMBER;
BEGIN
SELECT avg( TeamScore )
INTO avg_score
FROM TABLE( self.GamePlayed );
RETURN avg_score;
END;
END;
/
SQLFIDDLE

"PL/SQL: Function returned without value" A call to PL/SQL function completed, but no RETURN statement was executed

I've created a PL/SQL package with functions but when the package is called by passing the input values, then I get the following message:
Error report:
ORA-06503: PL/SQL: Function returned without value
ORA-06512: at "APPDATA.PWH_RELEASE_PAYMENT_ORDER_PKG", line 107
ORA-06512: at "APPDATA.PWH_RELEASE_PAYMENT_ORDER_PKG", line 158
ORA-06512: at line 36
06503. 00000 - "PL/SQL: Function returned without value"
*Cause: A call to PL/SQL function completed, but no RETURN statement was executed.*Action: Rewrite PL/SQL function, making sure that it always returns a value of a proper type.
Here's the package call being run:
/* Type Bank ID Collection */
CREATE OR REPLACE TYPE TYPE_BANKID_COLL
FORCE AS TABLE OF VARCHAR2(35 CHAR); -- Type BankId Collection
/
/* Type processing line collection */
create or replace TYPE TYPE_PROCESSINGLINE_COLL FORCE AS TABLE OF VARCHAR2(50 CHAR);
/
/* Type processing line ID collection */
CREATE OR REPLACE TYPE TYPE_PROCESSINGLINEID_COLL FORCE AS TABLE OF NUMBER;
/
/* Type Processing line flows - Object type 1 */
CREATE OR REPLACE TYPE TYPE_PROCESSINGLINEFLOWS FORCE AS OBJECT
(
processinglineid NUMBER,
processinglineflow TYPE_PROCESSINGLINEFLOW
);
/
-- 2 data types
/* Type Processing line flows coll - Nested table of Object type 1 */
CREATE OR REPLACE TYPE TYPE_PROCESSINGLINEFLOWS_COLL FORCE AS TABLE OF TYPE_PROCESSINGLINEFLOWS;
/
-- Type Processing line flows Collection
/* Type Processing line payment - Object type 2 */
create or replace TYPE TYPE_PROCESSINGLINEPAYMENT FORCE AS OBJECT
(
processingline VARCHAR2(50 CHAR),
processingLineFlows TYPE_PROCESSINGLINEFLOW_COLL,
messages TYPE_MESSAGE_COLL,
reservationRefs TYPE_RSVDTLS_COLL
);
/
/* Type Processing line payment Collection - Nested table of Object type 2 */
CREATE OR REPLACE TYPE TYPE_PROCESSINGLINEPAYMT_COLL FORCE AS TABLE OF TYPE_PROCESSINGLINEPAYMENT;
/
/* Type Bank due payment - Object type 3 */
CREATE OR REPLACE TYPE TYPE_BANKDUEDATEPAYMENT FORCE AS OBJECT
(
bankid VARCHAR2(35 CHAR),
payments TYPE_PROCESSINGLINEPAYMT_COLL
)
/
/* Type Bank due date payment Collection - Nested table of Object type 3 */
CREATE OR REPLACE TYPE TYPE_BANKDUEDATEPAYMENT_COLL FORCE AS TABLE OF TYPE_BANKDUEDATEPAYMENT;
/
/* Type POR Due date process */
CREATE OR REPLACE TYPE TYPE_PORDUEDATEPROCESS FORCE AS OBJECT
(
duedateid NUMBER,
payments TYPE_BANKDUEDATEPAYMENT_COLL
);
/
Here's the package code:
/* Start of package header - pwh release payment order pkg */
create or replace PACKAGE pwh_release_payment_order_pkg AS
/*
======================================================================================
Constants
======================================================================================
*/
c_readyForReservationEngine CONSTANT CHAR(4) := 'RFRE'; -- ready for reservation engine
c_readyForPaymentEngine CONSTANT CHAR(4) := 'RFPE'; -- ready for payment engine
-- releaseProcessOrder
FUNCTION releaseProcessOrder (
p_processinglines TYPE_PROCESSINGLINE_COLL, -- p_processinglines : TYPE_PROCESSINGLINES
/*
create or replace TYPE TYPE_PROCESSINGLINE_COLL FORCE AS TABLE OF VARCHAR2(50 CHAR);
*/
p_portype VARCHAR2, -- Type BankID Collection
p_banksinprocess TYPE_BANKID_COLL, -- Banks in process
/*
From the types file:
CREATE OR REPLACE TYPE TYPE_BANKID_COLL
FORCE AS TABLE OF VARCHAR2(35 CHAR);
*/
p_releasedate paymentinfo.releasedate%type, -- Release Date
p_paymentstatuses TYPE_PAYMENT_STATUS_COLL, -- Payment Statuses
p_processingdate duedateprocess.processingdate%type -- Type release payment order
) RETURN TYPE_PORDUEDATEPROCESS;
/* End of the package header */
END pwh_release_payment_order_pkg;
/
/* End of package header - End of pwh release payment order pkg */
/* Start of package body */
create or replace PACKAGE BODY pwh_release_payment_order_pkg
AS
FUNCTION getRsvDtlsForTransactions( /* get Reservation Details For Transactions */
p_transactionIds TYPE_TRANSACTIONID_COLL
) RETURN TYPE_RSVDTLS_COLL /* Type reservation details collection */
IS
v_reservationDetails TYPE_RSVDTLS_COLL := TYPE_RSVDTLS_COLL(); /* v_reservationDetails */
BEGIN
SELECT TYPE_RSVDTLS( reservationreference, reservationtime, reservedamount, currencycode, fk_transactionsid ) BULK COLLECT
/*
*/
INTO v_reservationDetails
FROM reservation_details rsvd
INNER JOIN TABLE(p_transactionIds) tids /* p_transactionIds - tids */
ON rsvd.fk_transactionsid = tids.COLUMN_VALUE;
RETURN v_reservationDetails; /* return v_reservationdetails */
END;
FUNCTION getProcessingLineFlows(
p_processingLineIds IN TYPE_PROCESSINGLINEID_COLL,
v_status OUT VARCHAR2
)RETURN TYPE_PROCESSINGLINEFLOWS_COLL
AS
v_processinglineflows TYPE_PROCESSINGLINEFLOWS_COLL := TYPE_PROCESSINGLINEFLOWS_COLL();
v_cnt NUMBER;
v_processingLineIds TYPE_PROCESSINGLINEID_COLL := TYPE_PROCESSINGLINEID_COLL();
BEGIN
SELECT TYPE_PROCESSINGLINEFLOWS(fk_processinglineid, TYPE_PROCESSINGLINEFLOW( FUNCTION, component )) BULK COLLECT
INTO v_processingLineFlows
FROM processinglineflow flow
INNER JOIN TABLE (p_processingLineIds) p
ON flow.fk_processinglineid = p.COLUMN_VALUE;
SELECT COUNT(flw.processinglineflow.function)
INTO v_cnt
FROM TABLE (v_processinglineflows) flw
WHERE flw.processinglineflow.function = 'FUND_CHECK';
IF v_cnt = p_processingLineIds.count THEN
SELECT COUNT(DISTINCT flw.processinglineflow.component)
INTO v_cnt
FROM TABLE (v_processinglineflows) flw
WHERE flw.processinglineflow.function = 'FUND_CHECK';
IF v_cnt = 1 THEN
v_status := c_readyForReservationEngine;
RETURN v_processingLineFlows;
END IF;
ELSIF v_cnt = 0 THEN
SELECT COUNT(flw.processinglineflow.function)
INTO v_cnt
FROM TABLE (v_processinglineflows) flw
WHERE flw.processinglineflow.function = 'PE_SELECTION';
IF v_cnt = 1 THEN
v_status := c_readyForPaymentEngine;
RETURN v_processingLineFlows;
END IF;
ELSE
raise_application_error (-20301, 'Invalid processing lines');
END IF;
END;
FUNCTION releaseProcessOrder(
p_processinglines TYPE_PROCESSINGLINE_COLL,
p_portype VARCHAR2,
p_banksinprocess TYPE_BANKID_COLL,
p_releasedate paymentinfo.releasedate%type,
p_paymentstatuses TYPE_PAYMENT_STATUS_COLL,
p_processingdate duedateprocess.processingdate%type
)RETURN TYPE_PORDUEDATEPROCESS
AS
v_status VARCHAR2(4 CHAR);
v_functionFundsCheck CHAR(10) := 'FUND_CHECK';
v_updatedTransactions TYPE_TRANSACTIONID_COLL := TYPE_TRANSACTIONID_COLL();
v_transactionids TYPE_TRANSACTIONID_COLL := TYPE_TRANSACTIONID_COLL();
v_transactionidsforpl TYPE_TRANSACTIONID_COLL := TYPE_TRANSACTIONID_COLL();
v_processinglineids TYPE_PROCESSINGLINEID_COLL := TYPE_PROCESSINGLINEID_COLL();
v_dueDateProcessId duedateprocess.duedateprocessid%type;
v_processingLineFlows TYPE_PROCESSINGLINEFLOWS_COLL := TYPE_PROCESSINGLINEFLOWS_COLL();
v_payments TYPE_BANKDUEDATEPAYMENT_COLL := TYPE_BANKDUEDATEPAYMENT_COLL();
v_releasepaymentorder TYPE_PORDUEDATEPROCESS;
v_flw TYPE_PROCESSINGLINEFLOW_COLL := TYPE_PROCESSINGLINEFLOW_COLL();
v_duepay TYPE_PROCESSINGLINEPAYMENT;
v_duepayments TYPE_PROCESSINGLINEPAYMT_COLL := TYPE_PROCESSINGLINEPAYMT_COLL();
BEGIN
SELECT p.processinglineid BULK COLLECT
INTO v_processinglineids
FROM processingline p
INNER JOIN TABLE(p_processinglines) pl
ON p.processingline = pl.COLUMN_VALUE;
v_processingLineFlows := getProcessingLineFlows(v_processinglineids,v_status);
v_dueDateProcessId := DUEDATE_ID_SEQ.NEXTVAL;
INSERT
INTO duedateprocess
(
duedateprocessid,
processingdate,
fk_processinglineid
)
SELECT v_dueDateProcessId,
NVL(p_processingdate,SYSDATE),
p.COLUMN_VALUE
FROM TABLE (v_processinglineids) p;
SELECT TYPE_PORDUEDATEPROCESS(v_dueDateProcessId,TYPE_BANKDUEDATEPAYMENT_COLL())
INTO v_releasepaymentorder
FROM DUAL;
IF p_portype = 'PrioritizedPOR' THEN
UPDATE transactions
SET paymentstatus = v_status -- If the por type is 'PrioritizedPOR',then paymentstatus is set to 'v_status'
WHERE paymentstatus IN ('RFDD','LAFU','TERE')
AND riskStatus IS NULL
AND fk_processinglineid IN (SELECT l.COLUMN_VALUE FROM TABLE(v_processinglineids)l)
AND fk_paymentinfoid IN
(SELECT paymentinfoid -- Select paymentinfo ID INNER JOIN the message table
FROM paymentinfo p
INNER JOIN MESSAGE m
ON m.messageid = p.fk_messageid -- Message m
AND p.releasedate <= SYSDATE -- releasedate is the current date
AND m.markettype = 'BM'
AND p.prioritized = 'Y'
AND p.paymentmethod IN ('TRF') AND categorypurposecode = 'INTC'
AND (p_banksinprocess IS NULL
OR initiatorbankid IN
(SELECT b.COLUMN_VALUE FROM TABLE(p_banksinprocess) b
))
) RETURNING transactionsid BULK COLLECT -- RETURNING transactionsid BULK COLLECT into v_updatedTransactions
INTO v_updatedTransactions;
ELSIF p_portype = 'CompletePOR' THEN
UPDATE transactions
SET paymentstatus = v_status
WHERE paymentstatus IN ('RFDD','LAFU','TERE')
AND riskStatus IS NULL
AND fk_processinglineid IN (SELECT l.COLUMN_VALUE FROM TABLE(v_processinglineids)l)
AND fk_paymentinfoid IN
(SELECT paymentinfoid
FROM paymentinfo p
INNER JOIN MESSAGE m
ON m.messageid = p.fk_messageid
AND p.releasedate <= SYSDATE
AND m.markettype = 'BM'
AND (p_banksinprocess IS NULL
OR initiatorbankid IN
(SELECT b.COLUMN_VALUE FROM TABLE(p_banksinprocess) b
))
) RETURNING transactionsid BULK COLLECT
INTO v_updatedTransactions;
ELSIF p_portype IS NULL THEN
UPDATE transactions
SET paymentstatus = v_status
WHERE paymentstatus IN (SELECT COLUMN_VALUE FROM TABLE(p_paymentstatuses))
AND riskStatus IS NULL
AND fk_paymentinfoid IN (
SELECT paymentinfoid
FROM paymentinfo
WHERE releasedate <= p_releasedate
AND fk_processinglineid = (SELECT l.COLUMN_VALUE FROM TABLE(v_processinglineids)l)
) RETURNING transactionsid
BULK COLLECT INTO v_updatedTransactions;
END IF;
IF v_updatedTransactions.COUNT = 0 THEN
raise_application_error (-20302, 'There are no payments to process for processing lines');
END IF;
INSERT INTO duedateprocesstotransactions (fk_duedateprocessid, fk_transactionsid)
SELECT v_dueDateProcessId, ut.COLUMN_VALUE
FROM TABLE(v_updatedTransactions) ut;
SELECT TYPE_BANKDUEDATEPAYMENT(initiatorbankid,TYPE_PROCESSINGLINEPAYMT_COLL()) BULK COLLECT
INTO v_payments
FROM transactions t
INNER JOIN paymentinfo p
ON p.paymentinfoid = t.fk_paymentinfoid
INNER JOIN MESSAGE m
ON m.messageid = p.fk_messageid
INNER JOIN TABLE(v_updatedTransactions) tid
ON t.transactionsid = tid.COLUMN_VALUE
GROUP BY m.initiatorbankid;
FOR i IN v_payments.FIRST..v_payments.LAST
LOOP
SELECT tid.COLUMN_VALUE BULK COLLECT
INTO v_transactionids
FROM transactions t
INNER JOIN paymentinfo p
ON p.paymentinfoid = t.fk_paymentinfoid
INNER JOIN MESSAGE m
ON m.messageid = p.fk_messageid
INNER JOIN TABLE(v_updatedTransactions) tid
ON t.transactionsid = tid.COLUMN_VALUE
AND m.initiatorbankid = v_payments(i).bankid;
FOR j IN v_processinglineids.FIRST..v_processinglineids.LAST
LOOP
SELECT TYPE_PROCESSINGLINEPAYMENT(processingline,TYPE_PROCESSINGLINEFLOW_COLL(),TYPE_MESSAGE_COLL(),TYPE_RSVDTLS_COLL())
INTO v_duepay
FROM PROCESSINGLINE
WHERE processinglineid = v_processinglineids(j);
SELECT TYPE_PROCESSINGLINEFLOW(plf.function,plf.component) BULK COLLECT
INTO v_flw
FROM processinglineflow plf
WHERE fk_processinglineid IN
(SELECT fk_processinglineid
FROM transactions t
INNER JOIN TABLE(v_transactionids)ut
ON t.transactionsid = ut.COLUMN_VALUE
AND t.fk_processinglineid = v_processinglineids(j)
);
v_duepay.processinglineflows := v_flw;
SELECT ut.COLUMN_VALUE BULK COLLECT
INTO v_transactionidsforpl
FROM transactions t
INNER JOIN TABLE(v_transactionids)ut
ON t.transactionsid = ut.COLUMN_VALUE
AND t.fk_processinglineid = v_processinglineids(j);
v_duepay.reservationRefs := getRsvDtlsForTransactions(v_transactionidsforpl);
v_duepay.messages := pwh_read_pkg.read_duedate_payments(v_transactionidsforpl);
v_duepayments.EXTEND;
v_duepayments(v_duepayments.COUNT):= v_duepay;
END LOOP;
v_payments(i).payments := v_duepayments;
END LOOP;
v_releasepaymentorder.payments := v_payments;
RETURN v_releasepaymentorder;
END;
END pwh_release_payment_order_pkg;
/
Why is the error getting generated ?
A better way to do this is to have a value of the return type initialized at the start of the function and the last statement in the function should return it.
This way there is only one return statement and it is always called unless there is an exception.
There also appears to be an issue with the nesting of your IF statements. They way they are nested does not guarantee that a RETURN statement will be reached.
The issue in your code is shown here where I abbreviate your code and annotate it.
FUNCTION getProcessingLineFlows(
p_processingLineIds IN TYPE_PROCESSINGLINEID_COLL,
v_status OUT VARCHAR2)
RETURN TYPE_PROCESSINGLINEFLOWS_COLL
AS
v_processinglineflows TYPE_PROCESSINGLINEFLOWS_COLL := TYPE_PROCESSINGLINEFLOWS_COLL();
v_cnt NUMBER;
v_processingLineIds TYPE_PROCESSINGLINEID_COLL := TYPE_PROCESSINGLINEID_COLL();
BEGIN
IF v_cnt = p_processingLineIds.count THEN
SELECT COUNT(DISTINCT flw.processinglineflow.component)
INTO v_cnt
FROM TABLE (v_processinglineflows) flw
WHERE flw.processinglineflow.function = 'FUND_CHECK';
IF v_cnt = 1 THEN
v_status := c_readyForReservationEngine;
--return from middle of the function
--hard to trace and debug
--and is the RETURN value initialized?
RETURN v_processingLineFlows;
END IF;
--if v_cnt is not 1 then nothing is returned from the branch above this
--the nested if loops are hard to track
ELSIF v_cnt = 0 THEN
SELECT COUNT(flw.processinglineflow.function)
INTO v_cnt
FROM TABLE (v_processinglineflows) flw
WHERE flw.processinglineflow.function = 'PE_SELECTION';
IF v_cnt = 1 THEN
v_status := c_readyForPaymentEngine;
--v_status is initialized but not necessarily your RETURN value
RETURN v_processingLineFlows;
END IF;
ELSE
raise_application_error (-20301, 'Invalid processing lines');
--if the no suitable values are found then nothing is returned
END IF;
Refer the create function documentation to find the correct syntax of definition.
CREATE FUNCTION : ORACLE
Make sure that every possible code path in every function has a RETURN. For example, in your getProcessingLineFlows function, you have a branch that starts:
IF v_cnt = p_processingLineIds.count THEN
SELECT COUNT(DISTINCT flw.processinglineflow.component)
INTO v_cnt
FROM TABLE (v_processinglineflows) flw
WHERE flw.processinglineflow.function = 'FUND_CHECK';
IF v_cnt = 1 THEN
v_status := c_readyForReservationEngine;
RETURN v_processingLineFlows;
END IF;
ELSIF v_cnt = 0 THEN
...
It is hard to read your code as formatted, but I believe that in the number of distinct flw.processinglineflow.component values is not exactly 1, then this function will exit without returning a value. I have no idea about your data or whether it is possible for that value to be anything other than 1 (although, if it's not, why are you checking it?). But this is the sort of code structure that causes the error you are asking about.
You need to do similar checks on all your code paths and make sure there is no way for any function to end without returning.

PL SQL how to select all columns

How do i make the following wrapper select all columns "*" instead of just if_type, and number_infected?
--spec
create or replace package WrapperSample is
type TResultRow is record(
if_type codes.cd%type
,number_infected Integer);
type TResultRowList is table of TResultRow;
function GetADedIcWarningsProv
(
p_hos_id in work_entity_data.hos_id%type
,p_date in date
) return TResultRowList
pipelined;
end WrapperSample;
/
--body
create or replace package body WrapperSample is
function GetADedIcWarningsProv
(
p_hos_id in work_entity_data.hos_id%type
,p_date in date
) return TResultRowList
pipelined is
v_refcur eOdatatypes_package.eOrefcur;
currentRow TResultRow;
begin
v_refcur := YourSchema.getADedIcWarningsProv(p_hos_id, p_date);
loop
fetch v_refcur
INTO currentRow;
exit when v_refcur%NotFound;
pipe row(currentRow);
end loop;
close v_refcur;
return;
end;
end WrapperSample;
/
I am not sure if I do understand your question and requirement.
But if you're looking for a way to get a table's content, or a portion thereof, this is probably how you would approach it:
create table tq84_test_table (
col_1 number,
col_2 varchar2(10),
col_3 date
);
insert into tq84_test_table values (1, 'one' , sysdate);
insert into tq84_test_table values (2, 'two' , sysdate+1);
insert into tq84_test_table values (3, 'three', sysdate-1);
create or replace package tq84_sss as
type record_t is table of tq84_test_table%rowtype;
function GetADedIcWarningsProv return record_t;
end;
/
create or replace package body tq84_sss as
function GetADedIcWarningsProv return record_t
is
ret record_t;
begin
select * bulk collect into ret
from tq84_test_table;
return ret;
end GetADedIcWarningsProv;
end;
/
You would then later use this function like so:
declare
table_content tq84_sss.record_t;
begin
table_content := tq84_sss.GetADedIcWarningsProv;
for i in 1 .. table_content.count loop
dbms_output.put_line(table_content(i).col_1 || ' ' ||
table_content(i).col_2 || ' ' ||
table_content(i).col_3
);
end loop;
end;
/
just use %rowtype
declare
...
someTableRow someTable%rowtype;
...
begin
select * into someTableRow from someTable where blah;
...