How can i fix a PLS-00306 ERROR inpl/sql? - sql

I want my function price data to takes the ids from the customers and for each item to make a special price..
example:
cust_id | item_id | price
30 14 11
30 25 4
31 14 12
31 25 6
CREATE OR REPLACE FUNCTION PRICE_DATA(
P_CUST_DATA_ID CUSTOMERS.CUSTOMERS_ID%TYPE,
P_ITEMS_DATA_ID ITEMS.ITEMS_ID%TYPE)
RETURN NUMBER AS
L_PRICE NUMBER;
BEGIN
dbms_random.seed(1000);
FOR i IN(SELECT CUSTOMERS_ID FROM CUSTOMERS) LOOP
FOR i IN(SELECT ITEMS_ID FROM ITEMS) LOOP
L_PRICE := ADD_PRICELIST(P_CUST_DATA_ID,
P_ITEMS_PRIC_ID,
ROUND(dbms_random.value(0,10),3));
END LOOP;
END LOOP;
RETURN L_PRICE;
END PRICE_DATA;
I run this script:
DECLARE
L_PRICE_ID NUMBER;
BEGIN
DELETE FROM PRICE;
L_PRICE_ID := PRICE_DATA;
END;
And i get a PLS-00306 ERROR in PRICE DATA

In your function, you have P_ITEMS_PRIC_ID it should be P_ITEMS_DATA_ID. You probably don't want to call both row variables i either.
Assuming your ADD_PRICELIST function does not have side-effects (it should not), you can rewrite it as:
CREATE OR REPLACE FUNCTION PRICE_DATA(
P_CUST_DATA_ID IN CUSTOMERS.CUSTOMERS_ID%TYPE,
P_ITEMS_DATA_ID IN ITEMS.ITEMS_ID%TYPE
)
RETURN NUMBER
AS
L_PRICE NUMBER;
BEGIN
dbms_random.seed(1000);
SELECT ADD_PRICELIST(
p_cust_data_id,
p_items_data_id,
ROUND(dbms_random.value(0,10),3)
)
INTO L_PRICE
FROM customers c
CROSS JOIN items i
ORDER BY c.customers_id DESC, i.items_id DESC
FETCH FIRST ROW ONLY;
RETURN L_PRICE;
END PRICE_DATA;
/
But that seems overkill as you do not use any values from the tables and are effectively just checking that at least one row exists in each table (and inefficiently calling ADD_PRICELIST multiple times) then you can simplify it to just checking the rows exist and then calling the function once:
CREATE OR REPLACE FUNCTION PRICE_DATA(
P_CUST_DATA_ID IN CUSTOMERS.CUSTOMERS_ID%TYPE,
P_ITEMS_DATA_ID IN ITEMS.ITEMS_ID%TYPE
)
RETURN NUMBER
AS
L_PRICE NUMBER;
l_exists NUMBER(1,0);
BEGIN
dbms_random.seed(1000);
SELECT CASE
WHEN EXISTS(SELECT 1 FROM customers)
AND EXISTS(SELECT 1 FROM items)
THEN 1
ELSE 0
END
INTO l_exists
FROM DUAL;
IF l_exists = 1 THEN
l_price := ADD_PRICELIST(
p_cust_data_id,
p_items_data_id,
ROUND(dbms_random.value(0,10),3)
);
END IF;
RETURN L_PRICE;
END PRICE_DATA;
/
Then you need to specify all the arguments when you call the function:
DECLARE
L_PRICE_ID NUMBER;
BEGIN
--DELETE FROM PRICE;
L_PRICE_ID := PRICE_DATA(3.14159, 2.71828);
DBMS_OUTPUT.PUT_LINE(l_price_id);
END;
/
db<>fiddle here

Related

pl/sql function to order string from varchar

function that take two parameters, the first to be a string and the second is the order (Asc or Desc) and the returned output to be ordering the first string as per the second parameter.
IN : dgtak
OUT: adgkt
Tried this but doesn't seem to work
CREATE OR REPLACE FUNCTION order_string(my_string IN VARCHAR2)
RETURN VARCHAR2 IS
ret_string VARCHAR2(4000);
BEGIN
SELECT LISTAGG(regexp_substr(my_string, '\w', 1, level), '') WITHIN
GROUP(
ORDER BY 1)
INTO ret_string
FROM dual
CONNECT BY regexp_substr(my_string, '\w', 1, level) IS NOT NULL;
RETURN ret_string;
END;
select order_string('dgtak') as RESULT from dual;
Here's one option:
SQL> create or replace function order_string (par_string in varchar2, par_order in varchar2)
2 return varchar2
3 is
4 retval varchar2(100);
5 begin
6 with temp (val) as
7 -- split PAR_STRING to rows
8 (select substr(par_string, level, 1)
9 from dual
10 connect by level <= length(par_string)
11 )
12 -- aggregate characters back in ascending or descending order
13 select case when par_order = 'Asc' then listagg(val, '') within group (order by val asc)
14 when par_order = 'Desc' then listagg(val, '') within group (order by val desc)
15 else null
16 end
17 into retval
18 from temp;
19
20 return retval;
21 end;
22 /
Function created.
Testing:
SQL> select order_string('dfag', 'Asc') result_asc,
2 order_string('dfag', 'Desc') result_desc
3 from dual;
RESULT_ASC RESULT_DESC
-------------------- --------------------
adfg gfda
SQL>
Just for fun, here's a procedural version. It has more lines of code than the SQL version but in my tests it's slightly faster.
create or replace function order_string
( p_string varchar2
, p_reverse varchar2 default 'N' )
return varchar2
as
pragma udf;
type letter_tt is table of number index by varchar2(1);
letters letter_tt := letter_tt();
letter varchar2(1);
sorted_string long;
string_length integer := length(p_string);
begin
-- Store all characters of p_string as indices of array:
for i in 1..string_length loop
letter := substr(p_string,i,1);
if letters.exists(letter) then
letters(letter) := letters(letter) +1;
else
letters(letter) := 1;
end if;
end loop;
-- Loop through array appending each array index to sorted_string
for i in indices of letters loop
for r in 1..letters(i) loop
sorted_string := sorted_string || i;
end loop;
end loop;
if p_reverse = 'Y' then
select reverse(sorted_string) into sorted_string from dual;
end if;
return sorted_string;
end order_string;
I've used the 21c indices of loop iterator, but you can write a conventional loop in earlier versions. You might also use two alternative loops for ascending and descending order in place of my hack.

Nested Loops In Oracle Not Work Correctly (Exceeds the maximum)

I wrote These Two queries For Sample Table to insert into "z_exp14_resualt" From "z_exp14_main ". The First Query Works Correctly (Null) But Second That For rows have due_date on the main table (Not Null), not works correctly! . I Think Problem is The loop. It started before the due date and even goes beyond that . For NOT Nulls Insert must start from today(year and monts from sysdate and day from opening_date) and continue until due_date
Calculate For Null DUE_DATES
declare
i number := 1;
BEGIN
for i in 1..12 loop
insert into z_exp14_resualt
select dep_id,ADD_MONTHS(ADD_MONTHS(opening_date,trunc( months_between (sysdate,opening_date))),i),rate*balance
from z_exp14_main
WHERE due_date IS null;
end loop;
END;
/
And For Not Null Due_dates
DECLARE
diff number;
x number :=1;
BEGIN
for i in (select * FROM z_exp14_main WHERE due_date IS NOT null) loop
diff :=trunc( months_between (sysdate,i.opening_date));
WHILE (ADD_MONTHS(ADD_MONTHS(i.opening_date,diff),x)<i.due_date) LOOP
insert into z_exp14_resualt
select dep_id,ADD_MONTHS(ADD_MONTHS(i.opening_date,diff),x),rate*balance
from z_exp14_main WHERE due_date is not null ;
x :=x+1;
end loop;
end loop;
end;
/
sample Date On Main (z_exp14_main)
--
DEP_ID
DUE_DATE
BALANCE
RATE
OPENING_DATE
--
20056634
null
283428
10
15-SEP-16
--
20056637
null
180222
10
07-NOV-14
--
20056639
null
58741
10
28-AUG-14
--
40000020
27-NOV-21
5000000
22
31-MAR-14
--
40000023
23-APR-21
63000000
22
25-AUG-18
The Problem Is In the "While" condition. I correct it And This Is Final Answer:
DECLARE
diff number;
x number ;
BEGIN
for i in (select * FROM z_exp14_main WHERE due_date IS NOT null) loop
diff :=trunc( months_between (sysdate,i.opening_date));
x:=0;
WHILE (add_months(sysdate,x)<i.due_date) LOOP
insert into z_exp14_resualt values (i.dep_id,ADD_MONTHS(ADD_MONTHS(i.opening_date,diff),x),(i.rate*i.balance) );
x :=x+1;
end loop;
end loop;
end;
/

When I try to call one procedure inside another procedure I got this sql error "no function with name 'PROC_DISPLAY_FIRSTNAME' exists in this scope "

I change my executable part as,
BEGIN
proc_ref_value(orders_id);
proc_display_firstname(custId);
DBMS_OUTPUT.PUT_LINE(orders_id||' '||status||' '||re_value||' '||cust_last_name );
END;
When I run It, I got output without customer full name.
Statement processed.
10101 completed 0 10102 cancelled 0 10103 completed 0
10104 completed 0 10105 refunded 740
But I want to get customer full name from first procedure.
This might be starting point based on what it seems you're trying to do with your code. You don't need procedures within your anonymous block, just cursors. Adjust variable types as you need.
DECLARE
orders_id CHAR(5);
status VARCHAR(10);
re_value NUMBER;
custId customer.customer_id%TYPE;
or_status orders.order_status%TYPE;
total orders.total_order%TYPE;
v_order_id orders.order_id%TYPE;
ref_value NUMBER;
customer_name varchar2(20);
CURSOR c1 IS
SELECT INITCAP(CONCAT(CONCAT(cust_first_name,' '),cust_last_name)) as cust_name
FROM customer
WHERE customer_id = cust_id;
CURSOR c2 IS
SELECT order_id
, order_status
, total_order
, CASE WHEN order_status='refunded' THEN total_order*0.25
WHEN order_status='completed' THEN total_order* 0
WHEN order_status='cancelled' THEN total_order*0
END order_value
FROM orders
where order_id = v_order_id;
BEGIN
v_order_id := 1; -- your value here
for x in c2 loop
or_status := x.order_status;
total := x.total_order;
ref_value := x.order_value;
for y in c1 loop
customer_name := y.cust_name;
end loop;
DBMS_OUTPUT.PUT_LINE(v_order_id||' '||or_status||' '||ref_value||' '||customer_name);
end loop;
END;

"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.

Bind variable error in SQL trigger

Here is my trigger.Following error.
45 /
SP2-0552: Bind variable "OLD" not declared.
I am unable to find the error .I have tried several times but failed.I have declared every variable but the error is showing.Someone please help me .
drop trigger DELETE_Single_food
CREATE OR REPLACE TRIGGER DELETE_Single_food
BEFORE DELETE ON SingleFoodOrder
FOR EACH ROW
declare
f_price number;
old_bill number;
f_quantity number;
p_bill number;
foodID number;
orderID number;
order_date Date;
s_date Date;
f_date Date;
f_dis number;
a number;
b number;
c number;
BEGIN
IF :old.H_delivery_ID is not NULL then
foodID := :old.Fooditem_ID;
orderID := :old.H_delivery_ID;
f_quantity := :old.Quantity;
select bill into old_bill from HomeDelivery where H_delivery_ID =orderID ;
select price into f_price from Food_Item where Fooditem_ID = foodID;
select discount_percentage into f_dis from Food_Item where Fooditem_ID = foodID;
select start_date into s_date from Food_Item where Fooditem_ID = foodID;
select deadline into f_date from Food_Item where Fooditem_ID = foodID;
select H_delivery_request into order_date from HomeDelivery where H_delivery_ID =orderID;
if f_dis is not NULL then
if (order_date >= s_date and order_date<=f_date) then
a := f_dis/100;
b := f_price*a ;
c := f_price-b;
p_bill := old_bill-( c*f_quantity);
update HomeDelivery set bill = p_bill where H_delivery_ID = orderID;
else
p_bill := old_bill-(f_price*f_quantity);
update HomeDelivery set bill = p_bill where H_delivery_ID = orderID;
end if;
else
p_bill := old_bill-(f_price*f_quantity);
update HomeDelivery set bill = p_bill where H_delivery_ID = orderID;
end if;
END;
/
The problem is not in your variables declarations. I think you're not closing your main IF statement:
IF :old.H_delivery_ID is not NULL then
I don't see the END IF for that one. Add END IF; before the END;
If this does not work, you will need to do some debugging. Try just to leave only that statement in the begin block.
CREATE OR REPLACE TRIGGER DELETE_Single_food
BEFORE DELETE ON SingleFoodOrder
FOR EACH ROW
BEGIN
IF :old.H_delivery_ID is not NULL then
null;
END IF;
END;
/
See if that compiles. Then add the rest of the code to see where it breaks.
Hope this helps!