Oracle Package Error - oracle

I want to create a package and inside the package we have a function having a parameter. I have table for TIME_DIM and the granularity of that table is one record/second. I am getting an error while crating this package any one help me on this.
create or replace
PACKAGE PKG_TIME_DIM
IS
Function FUN_TIME_DESC
( TIME_IN IN varchar2 )
RETURN varchar2
IS
TIMEDESC varchar2;
CURSOR c1
IS
SELECT TIME_DESC
from TIME_DIM
where TIME_DESC = TIME_IN;
BEGIN
open c1;
fetch c1 into TIME_DESC;
if c1%notfound then
TIMEDESC := 9999;
end if;
close c1;
RETURN TIMEDESC;
END;
END;

i don't know what error do you get but i see sevral problems:
by the declaration of the TIMEDESC variable the size of varchar2 is missing:
for Example: TIMEDESC varchar2(2000); or better
TIMEDESC TIME_DIM.TIME_DESC%TYPE;
there is a tipo in the following statment
fetch c1 into TIME_DESC;
you have declarated TIMEDESC and not TIME_DESC as the name of the variable
and may be the following is a problem
TIMEDESC := 9999;
TIMEDESC is of type varchar but you assigning number to it

There are many errors here. You appear to be declaring a package specification with code in it. You need both a specification and body. I've added comments on each line that had an issue:
-- Note: "CREATE OR REPLACE PACKAGE" = The specification
CREATE OR REPLACE PACKAGE PKG_TIME_DIM
IS
FUNCTION FUN_TIME_DESC (TIME_IN IN VARCHAR2) RETURN VARCHAR2;
END PKG_TIME_DIM;
/
-- Note: "CREATE OR REPLACE PACKAGE BODY" = Keyword BODY = the body
CREATE OR REPLACE PACKAGE BODY PKG_TIME_DIM
IS
FUNCTION FUN_TIME_DESC (TIME_IN IN VARCHAR2) RETURN VARCHAR2
IS
TIMEDESC VARCHAR2(100 CHAR); -- Need to define length of this variable in characters or bytes
CURSOR c1 IS
SELECT TIME_DESC
FROM TIME_DIM
WHERE TIME_DESC = TIME_IN;
BEGIN
OPEN c1;
FETCH c1 INTO TIMEDESC; -- Changed variable name to match the name you defined
IF c1%NotFound THEN
TIMEDESC := '9999'; -- Put quotes around this since this is a VARCHAR
END IF;
CLOSE c1;
RETURN TIMEDESC;
END FUN_TIME_DESC;
END PKG_TIME_DIM;
/

Related

what is wrong passing a record type as parameter

I have the following code snippets:
CREATE OR REPLACE PACKAGE pkg_test1 IS
TYPE t_rec1 is RECORD(c1 number);
FUNCTION f1(p1 t_rec1 ) RETURN VARCHAR2;
END pkg_test1;
CREATE OR REPLACE PACKAGE BODY pkg_test1 IS
FUNCTION f1 (p1 t_rec1) return varchar2 is
BEGIN
RETURN 'a';
END f1;
END pkg_test1;
DECLARE
TYPE t_rec IS RECORD (c1 NUMBER);
v_rec t_rec;
v_var VARCHAR2(15);
BEGIN
v_rec.c1 := 1;
v_var := pkg_test1.f1 (v_rec);
END;
When I execute the anonym code, I received the following error:
PLS-00306: wrong number or types of arguments in call to 'F1'
Can someone help me to see the mistake I make, please?
The type you declare in your anonymous block looks the same to you, but to Oracle it's a completely independent and incompatible type.
From the documentation:
A RECORD type defined in a package specification is incompatible with an identically defined local RECORD type.
You don't need it though; just use the package type:
DECLARE
-- don't create a new type....
--TYPE t_rec IS RECORD (c1 NUMBER);
--v_rec t_rec;
-- use the package type instead
v_rec pkg_test1.t_rec1;
v_var VARCHAR2(15);
BEGIN
v_rec.c1 := 1;
v_var := pkg_test1.f1 (v_rec);
END;
db<>fiddle

How to pass array as input parameter in Oracle Function

I have a function to BULK insert data using FORALL.
create or replace type l_array_tab as table of number;
create or replace FUNCTION fn_insert_using_array(
L_TAB VARCHAR2,
L_COL_NAME VARCHAR2,
L_ARRAY L_ARRAY_TAB)
RETURN NUMBER
AS
SQL_STMT VARCHAR2(32767);
sql_count NUMBER;
BEGIN
FORALL i IN L_ARRAY.first .. L_ARRAY.LAST
EXECUTE immediate 'INSERT INTO my_table
Select * from '||L_TAB
||' where '||L_COL_NAME||' := :1' using L_ARRAY(i);
sql_count:= SQL%ROWCOUNT;
RETURN SQL_COUNT;
end;
I need to call this function from another stored procedure or plsql block in this example. While calling this function, I am getting error as wrong number or type of inputs.
This is how I am calling the function:
create or replace type l_array_orig_tab as table of number;
Declare
l_array_orig l_array_orig_tab :=l_array_orig_tab();
l_tab varchar2(30): ='my_tab_orig';
l_col_name varchar2(30) :='insert_id';
V_COUNT NUMBER;
cursor c1 is select * from my_tab_orig;
begin
open c1;
LOOP
FETCH c1 BULK COLLECT INTO l_array_orig limit 1000;
EXIT WHEN L_ARRAY_orig.COUNT =0;
V_COUNT:= fn_insert_using_array(L_TAB, L_COL_NAME,l_array_orig);
END LOOP;
END ;
Please suggest how to call the function.
I am getting error as wrong number or type of inputs
You are getting the error because l_array_orig_tab is a different type from l_array_tab. It doesn't matter that they have the same structure, as far as Oracle knows they are different types. Oracle is a database engine and it strongly enforces type safety. There is no duck typing here.
So the simplest solution is to use the correct type when calling the function:
Declare
l_array_orig l_array_tab :=l_array_tab(); -- change this declaration
l_tab varchar2(30): ='my_tab_orig';
l_col_name varchar2(30) :='insert_id';
V_COUNT NUMBER;
cursor c1 is select * from my_tab_orig;
begin
open c1;
LOOP
FETCH c1 BULK COLLECT INTO l_array_orig limit 1000;
EXIT WHEN L_ARRAY_orig.COUNT =0;
V_COUNT:= fn_insert_using_array(L_TAB, L_COL_NAME,l_array_orig);
END LOOP;
END ;
"The function fn_insert_using_array is in a different schema and also the Type."
So the schema which owns the function has granted you EXECUTE privilege on the function. But they also need to grant you EXECUTE on the type. This is their responsibility: they defined the function with a UDT in its signature so they have to give you all the privileges necessary to call it.
I don't don't whether this is a toy example just for posting on SO, but if it isn't there is no need to create a type like this. Instead use the documented Oracle built-in table of numbers, sys.odcinumberlist.
Is l_array_orig_tab != l_array_tab
you have to use the same type or do the cast between type.
Declare
l_array_orig l_array_orig_tab;
new_array l_array_tab;
l_tab varchar2(30): ='my_tab_orig';
l_col_name varchar2(30) :='insert_id';
V_COUNT NUMBER;
cursor c1 is select * from my_tab_orig;
begin
open c1;
LOOP
FETCH c1 BULK COLLECT INTO l_array_orig limit 1000;
select cast( l_array_orig as l_array_tab) into new_array from dual;
EXIT WHEN L_ARRAY_orig.COUNT =0;
V_COUNT:= fn_insert_using_array(L_TAB, L_COL_NAME,new_array);
END LOOP;
END ;
How cast works.
select cast( variable as destination_type) into var_destination_type from dual

ORACLE APEX PL SQL Procedure Error

I keep getting a the error: success with compilation error. What am I doing wrong with my code? I tried it in sqlfiddle but I get an invalid SQL statement error. As far as I know, this is the correct syntax for PL/SQL
create or replace PROCEDURE PRC_CALC
(W_ORDERID_IN IN NUMBER)
AS
W_PARTSERVICEID VARCHAR2(10);
W_EXIST_FLAG NUMBER(1) :=0;
W_SUBTOTAL NUMBER(9) :=0;
W_TAX NUMBER(9) :=0.07;
W_DISCOUNT NUMBER(9) :=0;
W_TOTAL NUMBER(9) :=0;
BEGIN
SELECT COUNT(*)
INTO W_EXIST_FLAG
FROM tblJobOrders
WHERE fldOrderId = W_ORDERID_IN;
IF W_EXIST_FLAG = 1 THEN
CURSOR CUR_ORDERCHARGES IS
SELECT fldPartServiceId
FROM tblOrderCharges
WHERE fldOrderId = W_ORDERID_IN;
OPEN CUR_ORDERCHARGES;
LOOP
FETCH CUR_ORDERCHARGES
INTO W_PARTSERVICEID
EXIT WHEN CUR_ORDERCHARGES%NOTFOUND;
SELECT fldPartServiceAmount, fldDiscountPercent
INTO W_SUBTOTAL, W_DISCOUNT
FROM tblPartsServices
WHERE fldPartServiceId = W_PARTSERVICEID;
W_DISCOUNT := (W_SUBTOTAL*(W_DISCOUNT*.01));
W_TAX := (W_TOTAL*W_TAX);
W_TOTAL := W_SUBTOTAL - W_DISCOUNT;
W_TOTAL := W_TOTAL + W_TAX;
htp.prn('Your subtotal is: $' ||W_SUBTOTAL||'<br>');
htp.prn('Your Discount is: $' ||W_DISCOUNT||'<br>');
htp.prn('Your Tax is: $' ||W_TAX||'<br>');
htp.prn('Your Total is: $' ||W_TOTAL||'<br>');
END LOOP;
CLOSE CUR_ORDERCHARGES;
ELSE
htp.prn('The Order Id: '||W_ORDERID_IN||' does not exist in the database');
END IF;
END;
Your variable declarations need work
W_PARTSERVICEID VARCHAR2; should have a size such as W_PARTSERVICEID VARCHAR2(250);
Your number declarations will work but are better to specify a size as well
W_EXIST_FLAG NUMBER; should be W_EXIST_FLAG NUMBER(9);
W_EXIST_ORDER_FLAG is not declared and should be as well.
As a programming practice that goes beyond your question you should check that the values coming into the procedure and in the cursor are not null or zero.
The CURSOR CUR_ORDERCHARGES should be declared with the other declarations or put inside a new DECLARE BEGIN END block
and you are missing a semi colon when you FETCH the cursor, it should be
FETCH CUR_ORDERCHARGES
INTO W_PARTSERVICEID;
EXIT WHEN CUR_ORDERCHARGES%NOTFOUND;
The W_EXIST_ORDER_FLAG used in the first query is undefined. Perhaps, you meant W_EXIST_FLAG?

how to manually cache the values of function calls in 10g

I have the following code
CREATE OR REPLACE FUNCTION slow_function (p_in IN NUMBER)
RETURN NUMBER
AS
BEGIN
DBMS_LOCK.sleep(1);
RETURN p_in;
END;
/
CREATE OR REPLACE PACKAGE cached_lookup_api AS
FUNCTION get_cached_value (p_id IN NUMBER)
RETURN NUMBER;
PROCEDURE clear_cache;
END cached_lookup_api;
/
CREATE OR REPLACE PACKAGE BODY cached_lookup_api AS
TYPE t_tab IS TABLE OF NUMBER
INDEX BY BINARY_INTEGER;
g_tab t_tab;
g_last_use DATE := SYSDATE;
g_max_cache_age NUMBER := 10/(24*60); -- 10 minutes
-- -----------------------------------------------------------------
FUNCTION get_cached_value (p_id IN NUMBER)
RETURN NUMBER AS
l_value NUMBER;
BEGIN
IF (SYSDATE - g_last_use) > g_max_cache_age THEN
-- Older than 10 minutes. Delete cache.
g_last_use := SYSDATE;
clear_cache;
END IF;
BEGIN
l_value := g_tab(p_id);
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- Call function and cache data.
l_value := slow_function(p_id);
g_tab(p_id) := l_value;
END;
RETURN l_value;
END get_cached_value;
-- -----------------------------------------------------------------
-- -----------------------------------------------------------------
PROCEDURE clear_cache AS
BEGIN
g_tab.delete;
END;
-- -----------------------------------------------------------------
END cached_lookup_api;
/
I want to pass two parameters "pi_value1" and "pi_value2" both of varchar2 to the function slow_function instead of "p_in". Is is possible to cache the results with two in parameters in oracle 10g .
the above code works fine with 1 parameter.
Please any one explain?
You'd need to create a two-dimensional array type to cache the values. Something along the lines of this (omitting the cache expiration code since that isn't changing)
CREATE OR REPLACE PACKAGE BODY cached_lookup_api
AS
TYPE t_pi_value2_tbl IS TABLE OF NUMBER
INDEX BY VARCHAR2(100);
TYPE t_cache IS TABLE OF t_pi_value2_tbl
INDEX BY VARCHAR2(100);
g_cache t_cache;
FUNCTION get_cached_value( p_pi_value1 IN VARCHAR2,
p_pi_value2 IN VARCHAR2 )
IS
BEGIN
RETURN g_cache(p_pi_value1)(p_pi_value2);
EXCEPTION
WHEN no_data_found
THEN
g_cache(p_pi_value1)(p_pi_value2) := slow_function( p_pi_value1, p_pi_value2 );
RETURN g_cache(p_pi_value1)(p_pi_value2);
END;
END;

Calling a function in a before delete trigger

id like to call this function:
CREATE OR REPLACE PACKAGE orders_salary_manage2 AS
FUNCTION total_calc(p_order in NUMBER)
RETURN NUMBER;
END;
CREATE OR REPLACE PACKAGE BODY orders_salary_manage2 AS
tot_orders NUMBER;
FUNCTION total_calc(p_order in NUMBER)
RETURN NUMBER
IS
c_price product.unit_price%type;
c_prod_desc product.product_desc%type;
v_total_cost NUMBER := 0;
CURSOR c1 IS
SELECT product_desc, unit_price
FROM product
WHERE product_id IN (SELECT fk2_product_id
FROM order_line
WHERE fk1_order_id = p_order);
BEGIN
OPEN c1;
LOOP
FETCH c1 into c_prod_desc, c_price;
v_total_cost := v_total_cost + c_price;
EXIT WHEN c1%notfound;
END LOOP;
CLOSE c1;
return v_total_cost;
END;
from this trigger:
CREATE OR REPLACE TRIGGER trg_order_total
BEFORE DELETE ON placed_order
FOR EACH ROW
DECLARE
v_old_order NUMBER := :old.order_id;
BEGIN
total_calc(v_old_order);
END;
but i keep getting this error, note there is no error number just this:
Error at line 4: PL/SQL: Statement ignored
BEFORE DELETE ON placed_order
FOR EACH ROW
DECLARE
v_old_order NUMBER := :old.order_id;
BEGIN
im new to pl/sql and just not sure what is causing the problem. When a user deletes an order from the orders table the trigger should call the function to add up all the products on the order.
Thank you
(Considering your Package compiled with no errors) Use-
ret_val:= orders_salary_manage2.total_calc(v_old_order);
The ret_val must be a NUMBER since the package function total_calc returns a NUMBER. A function MUST always return its outcoume to a variable (like ret_val) depending on the type of the return value the data type of the variable must be declared.
The syntax to call Pacakaged Procedures and functions is -
<RETURN_VARIABLE> := PACKAGE_NAME.<FUNCTION_NAME>();
PACKAGE_NAME.<PROCEDURE_NAME>(); --Since Procedure never returns
Also note that if your package is in a different SCHEMA and has no PUBLIC SYNONYM then you will have to prefix the schema name like <SCHEMA>.PACKAGE_NAME.<FUNCTION_NAME>() (considering the calling schema has execute permissions on the package).
So,
CREATE OR REPLACE TRIGGER trg_order_total
BEFORE DELETE ON placed_order
FOR EACH ROW
DECLARE
v_old_order NUMBER := :old.order_id;
v_ret_val NUMBER := 0;
BEGIN
v_ret_val := orders_salary_manage2.total_calc(v_old_order);
--...Do stuff with v_ret_val
END;

Resources