Returning Oracle ref cursor and appending multiple results - oracle

I have this problem I'm hoping someone knows the answer to. I have an oracle stored procedure that takes a customer id and returns all the customer's orders in a ref_cursor. Oversimplifying it, this is what I have:
Orders
- orderId
- siteID
Customers
- siteID
- Name
GetOrder(siteID, outCursor) /* returns all orders for a customer */
Now, I need to write another procedure that takes a customer name and does a LIKE query to get all custIds, then I need to reuse the GetOrder method to return all the orders for the custIds found, something like this:
PROCEDURE GetOrderbyCustName(
p_name IN VARCHAR2,
curReturn OUT sys_refcursor
)
IS
siteid number;
BEGIN
FOR rec in SELECT site_id FROM customers WHERE name LIKE p_name
LOOP
-- This will replace curReturn in each iteration
-- how do I append instead?
GetOrder(rec.site_id,
curReturn
);
END LOOP;
END GetOrderbyCustName;
My question is, how do I append the return of GetOrder to curReturn in each iteration? As it's written right now it overwrites it in each cycle of the loop.
Thanks!!

You can't do it like that - cursors cannot be appended or merged. Just do this instead:
PROCEDURE GetOrderbyCustName(
p_name IN VARCHAR2,
curReturn OUT sys_refcursor
)
IS
BEGIN
OPEN curReturn FOR
SELECT o.orderID, o.siteID
FROM Orders o
JOIN Customers c ON c.siteID = o.siteID
WHERE c.name LIKE p_name;
END GetOrderbyCustName;

If the query is simple, I would say go with Tony's answer. This is not only simple but likely to perform better than executing one query for each siteID.
If it is fairly complex then it might be worth some extra effort to reuse the GetOrder procedure so you only have to maintain one query.
To do this, you would need to actually fetch the data from the refcursor on each iteration of the loop, and put it into some other data structure.
One option, if it makes sense for the interface, is to change GetOrderbyCustName to have a PL/SQL index-by table as its output parameter instead of a refcursor. Append to that table on each iteration through the loop.
If you really need to return a refcursor, you can use a nested table type instead and then return a cursor querying that nested table. Something like this (not tested code):
CREATE TYPE number_table_type AS TABLE OF NUMBER;
PROCEDURE GetOrderbyCustName(
p_name IN VARCHAR2,
curReturn OUT sys_refcursor
)
IS
cursor_source_table number_table_type := number_table_type();
single_site_cursor sys_refcursor;
orderID NUMBER;
BEGIN
FOR rec in SELECT site_id FROM customers WHERE name LIKE p_name
LOOP
-- This will replace curReturn in each iteration
-- how do I append instead?
GetOrder(rec.site_id,
single_site_cursor
);
-- Fetch all rows from the refcursor and append them to the nested table in memory
LOOP
FETCH single_site_cursor INTO orderID;
EXIT WHEN single_site_cursor%NOTFOUND;
cursor_source_table.extend();
cursor_source_table( cursor_source_table.COUNT+1) := orderID;
END LOOP;
END LOOP;
OPEN curReturn FOR
SELECT * FROM TABLE( cursor_source_table );
END GetOrderbyCustName;

Related

How to insert records into variables from cte in oracle?

I have a procedure in which I want to fetch all records from cte into Names variable. But this code is not writing into names from CTE. How can I fetch records into names so that I can later loop through names and get content of field_name?
CREATE OR REPLACE PROCEDURE sp_market
IS
Names VARCHAR2(32767);
BEGIN
WITH CTE(sqql) As
(
SELECT field_name sqql FROM pld_medicare_config
)
SELECT sqql into Names from CTE;
END sp_market;
SELECT sqql into Names from CTE;
You are assigning multiple rows returned from table to a variable, which will fail.
You could simply use a CURSOR FOR LOOP which will create an implicit cursor and you can loop through the names:
CREATE OR REPLACE PROCEDURE sp_market IS
BEGIN
FOR i IN (
SELECT field_name
FROM pld_medicare_config
)
LOOP
-- Your logic goes here
dbms_output.put_line(i.field_name);
END LOOP;
END;
/
I think your best bet is to create a associative array and use BULK COLLECT to populate the table. In its simplest form, the code would look like this:
CREATE OR REPLACE PROCEDURE sp_market IS
TYPE lt_names IS TABLE OF VARCHAR2(32767) INDEX BY PLS_INTEGER;
l_tNames lt_names;
BEGIN
SELECT field_name
BULK COLLECT INTO l_tNames
FROM pld_medicare_config
IF l_tNames.COUNT() > 0 THEN
FOR i IN l_tNames.FIRST..l_tNames.LAST LOOP
NULL; --REPLACE WITH YOUR LOGIC
END LOOP;
END IF;
END;
/
A few notes:
I'm assuming that you've set MAX_STRING_SIZE to EXTENDED. Otherwise, you'll have an issue with VARCHAR2 that big.
As I said, that is the simplest way to do this. If you're expecting a huge result set, you'll want to look into chunking it up. This Oracle blog post is very helpful in giving you multiple options for how to perform bulk processing. (Blog Post)

PL/SQL Creating a procedure that contains result set joins

I want to create a procedure in PL/SQL that has 5 steps. Step 1 and 2 execute first and return an ID. In step 3, we have a SELECT statement that has a condition with that returned ID. I want then to take all of the results of that SELECT statement and use them in a JOIN in another SELECT statement and use THOSE results in a 3rd SELECT statement again using JOIN. From what I've seen, I can't use CURSOR in JOIN statements. Some of my co-workers have suggested that I save the results in a CURSOR and then use a loop to iterate through each row and use that data for the next SELECT. However since I'm going to do 2 selects this will create a huge fork of inside loops and that's exactly what I'm trying to avoid.
Another suggestion was to use Temprary Tables to store the data. However this procedure could be executed at the same time by many users and the table's data would conflict with each other. Right now I'm looking at LOCAL Temporary tables that supposedly filter the data according the the session but I'm not really sure I want to create dummy tables for my procedures since I want to avoid leaving trash in the schema (this procedure is for a custom part of the application). Is there a standard way of doing this? Any ideas?
Sample:
DECLARE
USERID INT := 1000000;
TEXT1 VARCHAR(100);
TEXT_INDEX INT;
CURSOR NODES IS SELECT * FROM NODE_TABLE WHERE DESCRIPTION LIKE TEXT || '%';
CURSOR USERS IS SELECT * FROM USERGROUPS JOIN NODES ON NODES.ID = USERGROUPS.ID;
BEGIN
SELECT TEXT INTO TEXT1 FROM TABLE_1 WHERE ID = USERID;
TEXT_INDEX = INSTR(TEXT, '-');
TEXT = SUBSTR(TEXT, 0, TEXT_INDEX);
OPEN NODES;
OPEN USERS;
END;
NOTE: This does NOT work. Oracle doesn't support joins between cursors.
NOTE2: This CAN be done in a single query but for the sake of argument (and in my real use case) I want to break those steps down in a procedure. The sample code is a depiction of what I'm trying to achieve IF joins between cursors worked. But they don't and I'm looking for an alternative.
I ended up using a function (although a procedure could be used as well) along with tables. Things I've learned and one should pay attention to:
PL/SQL functions can only return types that have been declared in the schema in advance and are clear. You can't create a function that returns something like MY_TABLE%ROWTYPE, even though it seems the type information is available it is not acceptable. You have to instead create a custom type of MY_TABLE%ROWTYPE is you want to return it.
Oracle treats tables of declared types differently from tables of %ROWTYPE. This confused the hell out of me at first but from what I've gathered this is how it works.
DECLARE TYPE MY_CUSTOM_TABLE IS TABLE OF MY_TABLE%ROWTYPE;
Declares a collection of types of MY_TABLE row. In order to add to this we must use BULK COLLECT INTO from an SQL statement that queries MY_TABLE. The resulting collection CANNOT be used in JOIN statements is not queryable and CANNOT be returned by a function.
DECLARE
CREATE TYPE MY_CUSTOM_TYPE AS OBJECT (COL_A NUMBER, COL_B NUMBER);
CREATE TYPE MY_CUSTOM_TABLE AS TABLE OF MY_CUSTOM_TYPE;
my_custom_tab MY_CUSTOM_TABLE;
This create my_custom_tab which is a table (not a collection) and if populated can be queried at using TABLE(my_custmo_tab) in the FROM statement. As a table which is declared in advance in the schema this CAN be returned from a function. However it CANNOT be populated using BULK COLLECT INTO since it is not a collection. We must instead use the normal SELECT INTO statement. However, if we want to populate it with data from an existing table that has 2 number columns we cannot simply do SELECT * INTO my_custom_tab FROM DOUBLE_NUMBER_TABLE since my_custom_tab hasn't been initialized and doesn't contain enough rows to receive the data. And if we don't know how many rows a query returns we can't initialize it. The trick into populating the table is to use the CAST command and cast our select result set as a MY_CUSTOM_TABLE and THEN add it.
SELECT CAST(MULTISET(SELECT COL_A, COL_B FROM DOUBLE_NUMBER_TABLE) AS MY_CUSTOM_TABLE) INTO my_custom_tab FROM DUAL
Now we can easily use my_custom_tab in queries etc through the use of the TABLE() function.
SELECT * FROM TABLE(my_custom_tab)
is valid.
You can do such decomposition in many ways, but all of them have a significant performance penalty in comaration with single SQL statement.
Maintainability improvement are also questionable and depends on specific situation.
To review all possibilities please look through documentation.
Below is some possible variants based on simple logic:
calculate Oracle user name prefix based on given Id;
get all users whose name starts with this prefix;
find all tables owned by users from step 2;
count a total number of found tables.
1. pipelined
Prepare types to be used by functions:
create or replace type TUserRow as object (
username varchar2(30),
user_id number,
created date
)
/
create or replace type TTableRow as object (
owner varchar2(30),
table_name varchar2(30),
status varchar2(8),
logging varchar2(3)
-- some other useful fields here
)
/
create or replace type TUserList as table of TUserRow
/
create or replace type TTableList as table of TTableRow
/
Simple function to find prefix by user id:
create or replace function GetUserPrefix(piUserId in number) return varchar2
is
vUserPrefix varchar2(30);
begin
select substr(username,1,3) into vUserPrefix
from all_users
where user_id = piUserId;
return vUserPrefix;
end;
/
Function searching for users:
create or replace function GetUsersPipe(
piNameStart in varchar2
)
return TUserList pipelined
as
vUserList TUserList;
begin
for cUsers in (
select *
from
all_users
where
username like piNameStart||'%'
)
loop
pipe row( TUserRow(cUsers.username, cUsers.user_id, cUsers.created) ) ;
end loop;
return;
end;
Function searching for tables:
create or replace function GetUserTablesPipe(
piUserNameStart in varchar2
)
return TTableList pipelined
as
vTableList TTableList;
begin
for cTables in (
select *
from
all_tables tab_list,
table(GetUsersPipe(piUserNameStart)) user_list
where
tab_list.owner = user_list.username
)
loop
pipe row ( TTableRow(cTables.owner, cTables.table_name, cTables.status, cTables.logging) );
end loop;
return;
end;
Usage in code:
declare
vUserId number := 5;
vTableCount number;
begin
select count(1) into vTableCount
from table(GetUserTablesPipe(GetUserPrefix(vUserId)));
dbms_output.put_line('Users with name started with "'||GetUserPrefix(vUserId)||'" owns '||vTableCount||' tables');
end;
2. Simple table functions
This solution use same types as a variant with pipelined functions above.
Function searching for users:
create or replace function GetUsers(piNameStart in varchar2) return TUserList
as
vUserList TUserList;
begin
select TUserRow(username, user_id, created)
bulk collect into vUserList
from
all_users
where
username like piNameStart||'%'
;
return vUserList;
end;
/
Function searching for tables:
create or replace function GetUserTables(piUserNameStart in varchar2) return TTableList
as
vTableList TTableList;
begin
select TTableRow(owner, table_name, status, logging)
bulk collect into vTableList
from
all_tables tab_list,
table(GetUsers(piUserNameStart)) user_list
where
tab_list.owner = user_list.username
;
return vTableList;
end;
/
Usage in code:
declare
vUserId number := 5;
vTableCount number;
begin
select count(1) into vTableCount
from table(GetUserTables(GetUserPrefix(vUserId)));
dbms_output.put_line('Users with name started with "'||GetUserPrefix(vUserId)||'" owns '||vTableCount||' tables');
end;
3. cursor - xml - cursor
It's is a specific case, which may be implemented without user-defined types but have a big performance penalty, involves unneeded type conversion and have a low maintainability.
Function searching for users:
create or replace function GetUsersRef(
piNameStart in varchar2
)
return sys_refcursor
as
cUserList sys_refcursor;
begin
open cUserList for
select * from all_users
where username like piNameStart||'%'
;
return cUserList;
end;
Function searching for tables:
create or replace function GetUserTablesRef(
piUserNameStart in varchar2
)
return sys_refcursor
as
cTableList sys_refcursor;
begin
open cTableList for
select
tab_list.*
from
(
XMLTable('/ROWSET/ROW'
passing xmltype(GetUsersRef(piUserNameStart))
columns
username varchar2(30) path '/ROW/USERNAME'
)
) user_list,
all_tables tab_list
where
tab_list.owner = user_list.username
;
return cTableList;
end;
Usage in code:
declare
vUserId number := 5;
vTableCount number;
begin
select count(1) into vTableCount
from
XMLTable('/ROWSET/ROW'
passing xmltype(GetUserTablesRef(GetUserPrefix(vUserId)))
columns
table_name varchar2(30) path '/ROW/TABLE_NAME'
)
;
dbms_output.put_line('Users with name started with "'||GetUserPrefix(vUserId)||'" owns '||vTableCount||' tables');
end;
Of course, all variants may be mixed, but SQL looks better at least for simple cases:
declare
vUserId number := 5;
vUserPrefix varchar2(100);
vTableCount number;
begin
-- Construct prefix from Id
select max(substr(user_list.username,1,3))
into vUserPrefix
from
all_users user_list
where
user_list.user_id = vUserId
;
-- Count number of tables owned by users with name started with vUserPrefix string
select
count(1) into vTableCount
from
all_users user_list,
all_tables table_list
where
user_list.username like vUserPrefix||'%'
and
table_list.owner = user_list.username
;
dbms_output.put_line('Users with name started with "'||vUserPrefix||'" owns '||vTableCount||' tables');
end;
P.S. All code only for demonstration purposes: no optimizations and so on.

Oracle - select a specific column from a ref cursor

My situation:
I have a table named Table1. It has lots of columns, one of them is Column1. I don't know the other columns, they may even change sometimes.
There is a strongly typed ref cursor type which returns Table1%rowtype, named cur_Table1.
I have a stored procedure named SP1 which has an out parameter of type cur_Table1. I'm calling this SP1 stored procedure from another database that only sees this stored procedure, but not the table or the type itself.
How do I select only Column1 from the returned cursor?
I know I can fetch into a record or as many variables as the cursor has columns, but I only know of one column's existence so I can't declare the complete record or correct number of variables.
You can do this with DBMS_SQL, but it ain't pretty.
Table and sample data (COLUMN1 has the numbers 1 - 10):
create table table1(column1 number, column2 date, column3 varchar2(1000), column4 clob);
insert into table1
select level, sysdate, level, level from dual connect by level <= 10;
commit;
Package with a procedure that opens a ref cursor and selects everything:
create or replace package test_pkg is
type cur_Table1 is ref cursor return table1%rowtype;
procedure sp1(p_cursor in out cur_table1);
end;
/
create or replace package body test_pkg is
procedure sp1(p_cursor in out cur_table1) is
begin
open p_cursor for select column1, column2, column3, column4 from table1;
end;
end;
/
PL/SQL block that reads COLUMN1 data from the ref cursor:
--Basic steps are: call procedure, convert cursor, describe and find columns,
--then fetch rows and retrieve column values.
--
--Each possible data type for COLUMN1 needs to be added here.
--Currently only NUMBER is supported.
declare
v_cursor sys_refcursor;
v_cursor_number number;
v_columns number;
v_desc_tab dbms_sql.desc_tab;
v_position number;
v_typecode number;
v_number_value number;
begin
--Call procedure to open cursor
test_pkg.sp1(v_cursor);
--Convert cursor to DBMS_SQL cursor
v_cursor_number := dbms_sql.to_cursor_number(rc => v_cursor);
--Get information on the columns
dbms_sql.describe_columns(v_cursor_number, v_columns, v_desc_tab);
--Loop through all the columns, find COLUMN1 position and type
for i in 1 .. v_desc_tab.count loop
if v_desc_tab(i).col_name = 'COLUMN1' then
v_position := i;
v_typecode := v_desc_tab(i).col_type;
--Pick COLUMN1 to be selected.
if v_typecode = dbms_types.typecode_number then
dbms_sql.define_column(v_cursor_number, i, v_number_value);
--...repeat for every possible type.
end if;
end if;
end loop;
--Fetch all the rows, then get the relevant column value and print it
while dbms_sql.fetch_rows(v_cursor_number) > 0 loop
if v_typecode = dbms_types.typecode_number then
dbms_sql.column_value(v_cursor_number, v_position, v_number_value);
dbms_output.put_line('Value: '||v_number_value);
--...repeat for every possible type
end if;
end loop;
end;
/
Given the original question, jonearles's answer is still correct, so I'll leave it marked as such, but I ended up doing something completely different and much better.
The problem was/is that I have no control over SP1's database, I just have to call it from somewhere else as a 3rd party client. Now I managed to get permission to see not only SP, but also the type of the cursor. I still don't see the table but now there is a much cleaner solution:
In the other database I have been granted access to see this type now:
type cur_Table1 is ref cursor return Table1%rowtype;
So in my database I can do this now:
mycursor OtherDB.cur_Table1;
myrecord mycursor%rowtype;
...
OtherDB.SP1(mycursor);
fetch mycursor into myrecord;
dbms_output.put_line(myrecord.Column1);
See, I still don't need any access to the table, I see the cursor only. The key is that the magical %rowtype works for cursors as well, not just tables. It doesn't work on a sys_refcursor, but it does on a strongly typed one. Given this code, I don't have to care if anything changes on the other side, I don't have to define all the columns or records at all, I just specify the one column I'm interested in.
I really love this OOP attitude about Oracle.
Don't know if it's an option or not, but wouldn't a better solution be to create a function that returns the specific value you're looking for? That avoids the overhead of sending the extra data. Alternatively, you could define a cursor with a set of known fields in it that both parties know about.

use oracle cursor within a sys_refcursor

I've got a PL/SQL package that returns a sys_refcursor based on the id that you pass it. I'd like to iterate through some ids and create a new ref cursor with one column from the original result set repeated for each id. (Sort of a cross tab.) A very simplified version of the PL/SQL block looks like:
create or replace package body dashboard_package is
procedure visits(RC in out sys_refcursor, IdNumber varchar2) as
BEGIN
OPEN RC FOR
select *
from (
select cat, cat_order, subcat, label_text
, trim(to_char(sum(v.current_month),'9,999,999,999')) current_month
, trim(to_char(sum(v.ly_month),'9,999,999,999')) ly_month
, trim(to_char(sum(v.ytd_tot),'9,999,999,999')) ytd_tot
, trim(to_char(sum(v.lytd_tot),'9,999,999,999')) lytd_tot
, trim(to_char(sum(v.ly_tot),'9,999,999,999')) ly_tot
from dashboard v
where v.id_number = IdNumber
group by cat_order, subcat, cat, label_text
union all
...
) a
order by cat_order, subcat;
END;
END;
I think if I had something like this
create or replace procedure test_refcur is
refCursorValue SYS_REFCURSOR;
begin
dashboard_package.visits(refCursorValue,12345);
for cursrow in refCursorValue loop
dbms_output.put_line(cursrow.ytd_tot);
end loop;
end test_refcur;
working, I could take it from there... any thoughts? Or perhaps clarification on the question that I should be asking.
If you're coming in with a number of IDs, then first prize would be to run only one SQL query to fetch the lot in one go, using a bulk in-bind for the IDs. This would probably require a modification to dashboard_package.visits, or writing a new version of the visits procedure to accept a PL/SQL table of IDs instead of a single ID.
If your hands are tied WRT modifying dashboard_package, then you could write a pipelined function to return the rows for a set of IDs:
-- create some helper types for the pipelined function
create type visitobj as object
(id number
,cat dashboard.cat%type
,cat_order dashboard.cat_order%type
,subcat dashboard.subcat%type
,label_text dashboard.label_text%type
,current_month varchar2(13)
,ly_month varchar2(13)
,ytd_tot varchar2(13)
,lytd_tot varchar2(13)
,ly_tot varchar2(13));
create type visittable as table of visitobj;
create or replace function test_refcur
return visittable deterministic pipelined is
refCursorValue SYS_REFCURSOR;
cat dashboard.cat%type;
cat_order dashboard.cat_order%type;
subcat dashboard.subcat%type;
label_text dashboard.label_text%type;
current_month varchar2(13);
ly_month varchar2(13);
ytd_tot varchar2(13);
lytd_tot varchar2(13);
ly_tot varchar2(13);
begin
for id in (/*iterate through the IDs*/) loop
dashboard_package.visits(refCursorValue, id);
loop
fetch refCursorValue into cat, cat_order, subcat, label_text,
current_month, ly_month, ytd_tot,
lytd_tot, ly_tot;
exit when refCursorValue%NOTFOUND;
pipe row (visitobj (id, cat, cat_order, subcat, label_text,
current_month, ly_month, ytd_tot,
lytd_tot, ly_tot));
end loop;
end loop;
return;
end test_refcur;
-- now you can simply do this:
SELECT * FROM TABLE(test_refcur);
(Of course, "/*iterate through the IDs*/" would be whatever method you want to use to gather the IDs for which the function should be called - e.g. could be a PL/SQL table of IDs, or perhaps another query).
Again I'd stress that "first prize" is to not do any of this extra work at all - just have a dashboard_package.visits that does it all in one SQL.
On a side note, trim(to_char(sum(v.ly_tot),'9,999,999,999')) can be simplified to to_char(sum(v.ly_tot),'FM9,999,999,999'). Also, if you use the format 'FM9G999G999G999' instead, it will be non-locale-specific.

How to wrap an Oracle stored procedure in a function that gets executed by a standard SELECT query?

I am following these steps, but I continue to get an error and don't see the issue:
1) Create a custom Oracle datatype that represents the database columns that you want to retrieve:
CREATE TYPE my_object AS OBJECT
(COL1 VARCHAR2(50),
COL2 VARCHAR2(50),
COL3 VARCHAR2(50));
2) Create another datatype that is a table of the object you just created:
TYPE MY_OBJ_TABLE AS TABLE OF my_object;
3) Create a function that returns this table. Also use a pipeline clause so that results are pipelined back to the calling SQL, for example:
CREATE OR REPLACE
FUNCTION MY_FUNC (PXOBJCLASS varchar2)
RETURN MY_OBJ_TABLE pipelined IS
TYPE ref1 IS REF CURSOR
Cur1 ref1,
out_rec_my_object := my_object(null,null,null);
myObjClass VARCHAR2(50);
BEGIN
myObjClass := PXOBJCLASS
OPEN Cur1 For ‘select PYID, PXINSNAME, PZINSKEY from PC_WORK where PXOBJCLass = ;1’USING myObjClass,
LOOP
FETCH cur1 INTO out_rec.COL1, out_rec.COL2, out_rec.COL3;
EXIT WHEN Cur1%NOTFOUND;
PIPE ROW (out_rec);
END LOOP;
CLOSE Cur1;
RETURN;
END MY_FUNC;
NOTE: In the example above, you can easily replace the select statement with a call to another stored procedure that returns a cursor variable.
4) In your application, call this function as a table function using the following SQL statement:
select COL1, COL2, COL3 from TABLE(MY_FUNC('SomeSampletask'));
There is no need to use dynamic sql (dynamic sql is always a little bit slower) and there are too many variables declared. Also the for loop is much easier. I renamed the argument of the function from pxobjclass to p_pxobjclass.
Try this:
create or replace function my_func (p_pxobjclass in varchar2)
return my_obj_table pipelined
is
begin
for r_curl in (select pyid,pxinsname,pzinskey
from pc_work
where pxobjclass = p_pxobjclass) loop
pipe row (my_object(r_curl.pyid,r_curl.pxinsname,r_curl.pzinskey));
end loop;
return;
end;
EDIT1:
It is by the way faster to return a ref cursor instead of a pipelined function that returns a nested table:
create or replace function my_func2 (p_pxobjclass in varchar2)
return sys_refcursor
is
l_sys_refcursor sys_refcursor;
begin
open l_sys_refcursor for
select pyid,pxinsname,pzinskey
from pc_work
where pxobjclass = p_pxobjclass;
return l_sys_refcursor;
end;
This is faster because creating objects (my_object) takes some time.
I see two problems:
The dynamic query does not work that way, try this:
'select PYID, PXINSNAME, PZINSKEY from PC_WORK where PXOBJCLass ='''||PXOBJCLASS||''''
You don't need myObjClass, and it seems all your quotes are wrong.
The quoting on 'SomeSampletask'...
select COL1, COL2, COL3 from TABLE(MY_FUNC('SomeSampletask'));
Maybe I'm misunderstanding something here, but it seems like you want to be using a VIEW.

Resources