I have simple oracle function
create or replace function abs.test_func(test_in in number)
return number
is
test_out number ;
BEGIN
test_out:=test_in;
RETURN test_out;
END;
if I compile it - it compiles successfully.
but when I run from PLSQL Developer SQL Window
BEGIN abs.test_func(5); END;
it I gets the following errors
ORA-06550: line1, column8;
PLS-00221: 'TEST_FUNC' is not a procedure or is undefined
ORA-06550: line1, column8;
PL/SQL: Statement ignored
What's wrong with my function ?
Your create function code looks good, however you are not invoking the function properly. A function returns something, that you must either select, assign, print, or evaluate.
Here are a few examples of valid function calls:
-- print the return value
begin
dbms_output.put_line(test_func(5));
end;
/
1 rows affected
dbms_output:
5
-- select the return value
select test_func(5) from dual;
| TEST_FUNC(5) |
| -----------: |
| 5 |
Demo on DB Fiddle
We have kiosks for customers to check their purchase volume for two different categories of items. They will input their mobile number, which will send an OTP to their mobile numbers and they will input it back to authenticate, the system has to check the data and display for them. As a developer, the kiosk supplier has provided us with a limited functionality development kit by which we can execute select statement on the database and display the returned values on the kiosk.
I have created an object type as follows:
CREATE OR REPLACE TYPE rebate_values
AS
OBJECT (ASales_total number,
ACurrent_Rebate_Percent number,
ANeeded_Sales number,
ANext_Rebate_Percent number,
BSales_total number,
BCurrent_Rebate_Percent number,
BNeeded_Sales number,
BNext_Rebate_Percent number);
A function to which I will pass customers' mobile to get their sales and rebate information:
CREATE OR REPLACE FUNCTION AA_rebate_function (P_phone IN NUMBER)
RETURN rebate_values
IS
A_P_Sales_total NUMBER;
A_P_Current_Rebate_Percent NUMBER;
A_P_Needed_Sales NUMBER;
A_P_Next_Rebate_Percent NUMBER;
B_P_Sales_total NUMBER;
B_P_Current_Rebate_Percent NUMBER;
B_P_Needed_Sales NUMBER;
B_P_Next_Rebate_Percent NUMBER;
P_CODE VARCHAR (10);
BEGIN
SELECT CC_CODE
INTO P_CODE
FROM CUSTOMERS
WHERE C_MOBILE = P_phone;
FOR OUTDATA
IN (
--My Query to retrieve the data
Select ................
)
LOOP
IF OUTDATA.CLASS = 'X'
THEN
A_P_Sales_total := OUTDATA.SALES_TOTAL;
A_P_Current_Rebate_Percent := OUTDATA.CURRENT_REBATE_PERCENT;
A_P_Needed_Sales := OUTDATA.NEEDED_SALES_FOR_HIGHER_REBATE;
A_P_Next_Rebate_Percent := OUTDATA.NEXT_HIGHER_REBATE_PERCENT;
END IF;
IF OUTDATA.CLASS = 'Y'
THEN
B_P_Sales_total := OUTDATA.SALES_TOTAL;
B_P_Current_Rebate_Percent := OUTDATA.CURRENT_REBATE_PERCENT;
B_P_Needed_Sales := OUTDATA.NEEDED_SALES_FOR_HIGHER_REBATE;
B_P_Next_Rebate_Percent := OUTDATA.NEXT_HIGHER_REBATE_PERCENT;
END IF;
END LOOP;
RETURN rebate_values (A_P_Sales_total,
A_P_Current_Rebate_Percent,
A_P_Needed_Sales,
A_P_Next_Rebate_Percent,
B_P_Sales_total,
B_P_Current_Rebate_Percent,
B_P_Needed_Sales,
B_P_Next_Rebate_Percent);
END;
/
The query takes 27 seconds to retrieve the values for each customer. Each customer will have 2 rows, so that's why I have used LOOP to collect the values.
When I execute the function:
SELECT AA_rebate_function (XXXXXXXXXX) FROM DUAL;
I get data as follows in a single column within 27 seconds:
(XXXX, X, XXXX, X, XXXX, X, XXXX, X)
But when I execute the function to get the values in different columns, it takes 27 x 8 seconds = 216 seconds, i.e., approximately 3.6 minutes which is a big issue as the customer cannot wait for 3.6 minutes on the kiosk to view the data.
SELECT x.c.ASales_total,
x.c.ACurrent_Rebate_Percent,
x.c.ANeeded_Sales,
x.c.ANext_Rebate_Percent,
x.c.BSales_total,
x.c.BCurrent_Rebate_Percent,
x.c.BNeeded_Sales,
x.c.BNext_Rebate_Percent
FROM (SELECT AA_rebate_function (XXXXXXXXXX) c FROM DUAL) x;
I have tried using stored procedure with OUT values but it doesn't fit in my environment as I cannot program to execute stored procedures from the kiosk development toolkit because it only supports select statements, checked with the supplier and they don't have any plan to add that support in near future.
I tried converting the single field into multiple columns using REGEXP_SUBSTR but I get a type conversion error as it is an array.
The query is very complex and has to calculate data for the last 10 years and has millions of rows, 27 seconds is actually the optimum time to get the desired results.
Interesting! I didn't realize that when you query a function that returns an object, it runs the function once for each column you reference the object in. That's awkward.
The easiest solution I could find for this is to switch your function to be PIPELINED. You'll need to create a nested table type to do this.
create type rebate_values_t is table of rebate_values;
/
CREATE OR REPLACE FUNCTION AA_rebate_function (P_phone IN NUMBER)
RETURN rebate_values_t PIPELINED
IS
... your code here ...
PIPE ROW (rebate_values (A_P_Sales_total,
A_P_Current_Rebate_Percent,
A_P_Needed_Sales,
A_P_Next_Rebate_Percent,
B_P_Sales_total,
B_P_Current_Rebate_Percent,
B_P_Needed_Sales,
B_P_Next_Rebate_Percent));
RETURN;
END;
/
SELECT x.ASales_total,
x.ACurrent_Rebate_Percent,
x.ANeeded_Sales,
x.ANext_Rebate_Percent,
x.BSales_total,
x.BCurrent_Rebate_Percent,
x.BNeeded_Sales,
x.BNext_Rebate_Percent
FROM TABLE(AA_rebate_function (XXXXXXXXXX)) x;
For some reason, this should only execute the function once, and take 27 seconds.
I am trying to produce a report that calculates a discount applied to an order using a stored function in Oracle 12c. I have a table, orders with column o_id. Each line of the order is a separate order_line table, having o_id, ol_quantity, and ol_price. If the order is over $100, a discount of $10 is applied to the order.
I have created a stored function, which compiles, but when I try to run the function I get the error:
Error(10,1): PLS-00103: Encountered the symbol "FINAL_COST" when expecting one of the following: * & - + / at mod remainder rem then <an exponent (**)> and or || multiset
Here is the function:
create or replace function DiscountsReport
(order_id IN REAL) RETURN REAL
is
percent real;
final_cost real;
being
select SUM(order_line.ol_quantity * order_line.ol_price) as total from order_line
where o_id = order_id;
if total >= 100 final_cost = 90;
return final_cost;
end;
And my code to run it is:
var cost number;
execute :cost := discountsreport(1);
print cost;
Your "if" statement is absolutely incorrect. Take a look at the documentation:
if-then-else
I have one stored Procedure P_FP_GET_PATTERN.I expect output in following format
PATTERN_ID |PATTERN_NAME | SHIFT
1 Pattern 1 A,B,C,B,A
2 Pattern 2 C,B,A,C
I'm getting this output in SYS_REFCURSOR ALL_RESULT_SET.I need to pass it in XML format.But the moment i put that output in ALL_RESULT_SET_XML which is my out parameter of stored procedure of XMLTYPE using ALL_RESULT_SET_XML:= XMLTYPE(ALL_RESULT_SET);
Im getting an error as
Error encountered: ORA-31061: XDB error: special char to escaped char conversion failed.
I`m getting this error due to column shown using LISTAGG() function.Anybody can please tell me how to handle this ?
My stored Procedure
create or replace
PROCEDURE P_FP_GET_PATTERN
(
ALL_RESULT_SET_XML OUT XMLTYPE,
P_MESSAGE_ALL OUT VARCHAR2
)
AS
V_ERROR VARCHAR2(2000);
ALL_RESULT_SET SYS_REFCURSOR;
BEGIN
OPEN ALL_RESULT_SET FOR
SELECT PM.PATTERN_ID ,PM.PATTERN_NAME,
LISTAGG(SM.SHIFT_NUMBER) WITHIN GROUP (ORDER BY PD.INSTANCE_DAY) "SHIFT"
FROM T_FP_PATTERN_MASTER PM,
T_FP_PATTERN_DETAILS PD,
T_FP_SHIFT_MASTER SM
WHERE SM.SHIFT_ID= PD.SHIFT_ID
AND PM.PATTERN_ID = PD.PATTERN_ID
GROUP BY PM.PATTERN_NAME,PM.PATTERN_ID;
--Adding output in XML output parameter
ALL_RESULT_SET_XML:= XMLTYPE(ALL_RESULT_SET);
EXCEPTION
WHEN OTHERS
THEN
V_ERROR := SUBSTR(SQLERRM,1,1000);
P_MESSAGE_ALL := 'Error encountered: '||V_ERROR ;
END;
SQL> CREATE or REPLACE FUNCTION custord (custNo IN number)
2 RETURN NUMBER
3 IS cust_tot NUMBER(11,2);
4 BEGIN
5 SELECT sum(cust_total_field)
6 INTO cust_tot
7 FROM ord
8 WHERE cust_number_field=custNo;
9 RETURN(cust_tot);
10 END;
11 /
Warning: Function created with compilation errors.
SQL> begin
2 dbms_output.put_line('customer 102 total is ' || custord(102));
3 end;
4 /
dbms_output.put_line('customer 102 total is ' || custord(102));
*
ERROR at line 2:
ORA-06550: line 2, column 52:
PLS-00905: object CIS605.CUSTORD is invalid
ORA-06550: line 2, column 3:
PL/SQL: Statement ignored
SQL>
I see the error but object cis605 is valid. Any ideas what I am missing?
Using the ORD table create a stored function called custord that will use a customer id (CUSTID) that will return the sum of the specified customer id TOTAL field.
When your function has been stored run the following SQL:
begin
dbms_output.put_line('customer 102 total is ' || custord(102));
end;
Your output should look like:
Results
Explain
Describe
Saved SQL
History
customer 102 total is 27775.5
Statement processed.
Try
SHOW ERRORS FUNCTION custord
Your custord function was created with compilation errors, so there is something wrong with it. This is why you're getting the object CIS605.CUSTORD is invalid error.