I want to use the cursor in the package's function like this:
PACKAGE PKG
AS
TYPE RESULT_T
IS
TABLE OF varchar2(30);
FUNCTION GENERATEF
RETURN RESULT_T PIPELINED;
END PKG;
/
create or replace
PACKAGE BODY PKG
AS
FUNCTION GENERATEF
RETURN RESULT_T PIPELINED
IS
BEGIN
FOR TLC IN (select name from users)
LOOP
PIPE ROW(TLC.name);
END LOOP;
RETURN;
END;
END PKG;
/
SELECT * FROM TABLE(PKG.GENERATEF);
I think right now the issue is focusing on the
select name from users
because if I use
select sysdate from dual
the function works well.
If I want to extract data from other VIEW, it will bring some error like this:
Error(7,45): PL/SQL: ORA-00942: table or view does not exist".
But actually, the view exists.
I don't know where is the problem. And I'm not sure whether it's OK to use the cursor like I mentioned.
Related
What would be the PL/SQL equivalent of this SQL query:
SELECT * FROM table(OWNER.PACKAGE.get_exam('123456789'));
This is the Function that I am trying to call:
FUNCTION get_exam(id IN VARCHAR2)
RETURN ab_assign_v1
IS
CURSOR c_exams(cid VARCHAR2) IS
SELECT t_api_exam_v1(
sei.person_id, --unique id
l.description --loc description
)
FROM my_view sei
JOIN loc l
ON sei.loc_code = l.loc_code
v_collection ab_assign_v1;
BEGIN
OPEN c_exams(id);
FETCH c_exams BULK COLLECT INTO v_collection;
CLOSE c_exams;
RETURN v_collection;
EXCEPTION
WHEN OTHERS THEN
error_a1.raise_error(SQLCODE, SQLERRM);
END get_exam;
Hope this helps.
DECLARE
lv <COLLECTION_NAME>;
BEGIN
lv:= OWNER.PACKAGE.get_exam('123456789');
dbms_output.put_line(lv.COUNT);
END;
/
Assuming that you want to return the result of a function :
select owner.package.get_exam('123456789') from table
Your function returns a nested table type. You simply need to declare a variable of that type, and assign to it as you would if it were a scalar:
declare
l_coll your_collection_type;
begin
l_coll := OWNER.PACKAGE.get_exam('123456789');
end;
/
In this example your_collection_type is a placeholder for whatever object your function actually returns.
" I am getting this error: PLS-00201: identifier 'ab_assign_v1' must be declared "
ab_assign_v1 is the type used by your function. From the code posted in your revised question it seems that type is in the same schema which owns the package with the function. However your original pseudo-code prefixes the call with the schema name. So, putting two and two together, you need to revise the variable declaration to include the schema too. (You may need to grant EXECUTE on it too, if you haven't done this already).
declare
l_coll OWNER.ab_assign_v1;
begin
l_coll := OWNER.PACKAGE.get_exam('123456789');
end;
/
I have the following script which contains a function named 'myFunction'. (declaration of types named rowValueTmp and rowValueTable are also attached for your information) Basically, I need to use a table name as an input parameter for myFunction. I found that I need to use dynamic SQL in order to use the table name as a parameter (Please correct me if there are alternative ways to do this). So the following code is what I have tried so far.
create or replace type rowValueTmp as object (
month number,
year number
);
/
create or replace type rowValueTable as table of rowValueTmp;
/
create or replace FUNCTION myFunction (TABLENAME in VARCHAR2)
return rowValueTable as
v_ret rowValueTable;
begin
execute immediate '
select rowValueTmp(month, year)
bulk collect into v_ret
from '||TABLENAME;
return v_ret;
end myFunction;
/
select * from table(myFunction('SCHEMA.TEST'));
But, this code gives me an error, and I assumed that this error is occurred because of using 'bulk collect' in execute immediate block.
ORA-03001: unimplemented feature
If I replace the content of execute immediate as the following, the above script is working..
select rowValueTmp(month, year)
bulk collect into v_ret
from SCHEMA.TEST;
Question
1] Is there any way(rather than Dynamic SQL) that I can use a table name as an input parameter for myFunction?
2] If I am not allowed to use bulk collect in execute immediate block, what do you suggest?
You can return values from execute immediately into a bulk collect:
CREATE OR REPLACE FUNCTION myfunction (tablename IN VARCHAR2)
RETURN rowvaluetable AS
v_ret rowvaluetable;
v_table VARCHAR2 (61) := DBMS_ASSERT.sql_object_name (tablename);
BEGIN
EXECUTE IMMEDIATE '
select rowValueTmp(month, year)
from ' || v_table
BULK COLLECT INTO v_ret;
RETURN v_ret;
END myfunction;
/
In the interest of an abundance of caution, I'd recommend using DBMS_ASSERT to validate the table parameter as well (as shown).
I have a package body as give bellow. I need to call a function named TESTING() inside the function body and call another query. Code is given bellow
CREATE OR REPLACE PACKAGE BODY TEST_PCAKAGE AS -- body
FUNCTION OUTER_FUNCTION (
INPUT_A IN VARCHAR2,
INPUT_B IN DATE,
) RETURN REF_CURSOR_TYPE IS
CUR_CA_RECEIPTS REF_CURSOR_TYPE;
BEGIN
OPEN CUR_CA_RECEIPTS FOR
TESTING();
SELECT * FROM TEST_TABLE;
RETURN CUR_CA_RECEIPTS;
END OUTER_FUNCTION;
END TEST_PCAKAGE ;
when creating this package body, it gives me errors. Can anyone please tell me how to do this?
Error : Error(14,1): PLS-00428: an INTO clause is expected in this SELECT statement
create or replace
FUNCTION "TESTING" RETURN VARCHAR2
AS
BEGIN
RETURN('SUCCESS');
END;
I'm guessing you'r trying to return the cursor from the function
Try this :
CREATE OR REPLACE PACKAGE BODY TEST_PCAKAGE AS -- body
FUNCTION OUTER_FUNCTION (
INPUT_A IN VARCHAR2,
INPUT_B IN DATE,
) RETURN REF_CURSOR_TYPE IS
-- use sys_refcursor for dynamic cursors
CUR_CA_RECEIPTS sys_refcursor;
BEGIN
-- Open the cursor for a query and not a function
OPEN CUR_CA_RECEIPTS FOR SELECT * FROM TEST_TABLE;
-- i'm guessing this is for debug
TESTING();
-- you can now iterate it in a different procedure
RETURN CUR_CA_RECEIPTS;
END OUTER_FUNCTION;
END TEST_PCAKAGE ;
If I write a simple function doSomething, I can get its result by executing :
select doSomething() from dual;
But, if I wish to call a procedure that has an OUT cursor being passed to it (along with another int parameter), how do I call that procedure inside a query and access the result of the cursor ?
Calling it inside a query is not compulsory.. its just that I want to access the results of that procedure
You can create a procedure like
CREATE OR REPLACE PROCEDURE your_procedure(out_cursor OUT sys_refcursor)
IS
BEGIN
OPEN out_cursor FOR
SELECT employee_name
FROM employees;
END;
/
Once you create your procedure wrap the procedure in a function which returns a cursor like the following
CREATE OR REPLACE FUNCTION your_function
RETURN sys_refcursor
AS
o_param sys_refcursor;
BEGIN
o_param := NULL;
your_procedure(o_param);
RETURN o_param;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
-- raise
WHEN OTHERS
THEN
-- raise
END your_function;
/
To see the results from sql do as
select your_function from dual;
Update 1
To see result in SQL Developer
Step 1
Double click on your results in SQL Developer
[Results][1]
Step 2 Single Click on the button with dots. That will pop up the values
[Grid][2]
You can Do Something Like This
select doSomething(cursor (select int_col from your_table)) colname from dual
Hope this Help
I am very new to DB. I am java developer and nothing to do with SQL Functions.
But now I am in a situation where I need to check whether an sql function is getting executed properly on db or not
CREATE OR REPLACE FUNCTION RATELIMIT_OWN.Get_Logs ( p_yyyymm VARCHAR2, p_numec NUMBER )
RETURN LOG_RECORD_TABLE PIPELINED IS
TYPE ref0 IS REF CURSOR;
cur0 ref0;
out_rec LOG_RECORD := log_record(NULL,NULL,NULL);
BEGIN
OPEN cur0 FOR
'SELECT eventid, errormsg, create_date from logs partition (LOGS_P' || p_yyyymm || ') where numec=:1'
USING p_numec;
LOOP
FETCH cur0 INTO out_rec.eventid, out_rec.msg, out_rec.create_date;
EXIT WHEN cur0%NOTFOUND;
PIPE ROW(out_rec);
END LOOP;
CLOSE cur0;
RETURN;
END Get_Logs;
/
How to execute this sql function in toad. I want to see the results like normal Select query output
To check a table valued function please try:
select * FROM table(RATELIMIT_OWN.Get_Logs('a', 1));
FOE EXECUTING THE FUNCTION
SELECT RATELIMIT_OWN.Get_Logs(....,...) FROM DUAL ;
AND
ORA-00904: MEAN COLUMN NAME IS NOT VALID PLSS CHECK THE COLUMN NAME
Try:
select RATELIMIT_OWN.Get_Logs(...) from dual;