Order by in a table function
I just wanted to verify that the order by works in a table function. It somehow seems not to work for me.
the function is of the form.
function getData(in_cursor SYS_REFCURSOR)
return T_DATA_S
PIPELINED
IS
begin
-- do stuff
return;
end;
and i call the function in a sql query like this
select * from TABLE(getData(CURSOR(select * from table order by date desc)))
The problem is the final output does not have an order by the date, is this a known issue somewhere or am i making a mistake some place.
What version are you using? I tried it in 9i and it works.
SQL> SELECT a1, b1 FROM TABLE(f_function(CURSOR(select a, b from t_table order by a)))
2 /
A1 B1
1 D
2 C
3 B
4 A
4 rows selected.
SQL> SELECT a1, b1 FROM TABLE(f_function(CURSOR(select a, b from t_table order by b)))
2 /
A1 B1
4 A
3 B
2 C
1 D
4 rows selected.
SQL> disconnect
Disconnected from Oracle9i Enterprise Edition Release 9.2.0.4.0 - 64bit Production
With the Partitioning option
JServer Release 9.2.0.4.0 - Production
SQL>
Similar Messages
-
Performance issues with pipelined table functions
I am testing pipelined table functions to be able to re-use the <font face="courier">base_query</font> function. Contrary to my understanding, the <font face="courier">with_pipeline</font> procedure runs 6 time slower than the legacy <font face="courier">no_pipeline</font> procedure. Am I missing something? The <font face="courier">processor</font> function is from [url http://www.oracle-developer.net/display.php?id=429]improving performance with pipelined table functions .
Edit: The underlying query returns 500,000 rows in about 3 minutes. So there are are no performance issues with the query itself.
Many thanks in advance.
CREATE OR REPLACE PACKAGE pipeline_example
IS
TYPE resultset_typ IS REF CURSOR;
TYPE row_typ IS RECORD (colC VARCHAR2(200), colD VARCHAR2(200), colE VARCHAR2(200));
TYPE table_typ IS TABLE OF row_typ;
FUNCTION base_query (argA IN VARCHAR2, argB IN VARCHAR2)
RETURN resultset_typ;
c_default_limit CONSTANT PLS_INTEGER := 100;
FUNCTION processor (
p_source_data IN resultset_typ,
p_limit_size IN PLS_INTEGER DEFAULT c_default_limit)
RETURN table_typ
PIPELINED
PARALLEL_ENABLE(PARTITION p_source_data BY ANY);
PROCEDURE with_pipeline (argA IN VARCHAR2,
argB IN VARCHAR2,
o_resultset OUT resultset_typ);
PROCEDURE no_pipeline (argA IN VARCHAR2,
argB IN VARCHAR2,
o_resultset OUT resultset_typ);
END pipeline_example;
CREATE OR REPLACE PACKAGE BODY pipeline_example
IS
FUNCTION base_query (argA IN VARCHAR2, argB IN VARCHAR2)
RETURN resultset_typ
IS
o_resultset resultset_typ;
BEGIN
OPEN o_resultset FOR
SELECT colC, colD, colE
FROM some_table
WHERE colA = ArgA AND colB = argB;
RETURN o_resultset;
END base_query;
FUNCTION processor (
p_source_data IN resultset_typ,
p_limit_size IN PLS_INTEGER DEFAULT c_default_limit)
RETURN table_typ
PIPELINED
PARALLEL_ENABLE(PARTITION p_source_data BY ANY)
IS
aa_source_data table_typ;-- := table_typ ();
BEGIN
LOOP
FETCH p_source_data
BULK COLLECT INTO aa_source_data
LIMIT p_limit_size;
EXIT WHEN aa_source_data.COUNT = 0;
/* Process the batch of (p_limit_size) records... */
FOR i IN 1 .. aa_source_data.COUNT
LOOP
PIPE ROW (aa_source_data (i));
END LOOP;
END LOOP;
CLOSE p_source_data;
RETURN;
END processor;
PROCEDURE with_pipeline (argA IN VARCHAR2,
argB IN VARCHAR2,
o_resultset OUT resultset_typ)
IS
BEGIN
OPEN o_resultset FOR
SELECT /*+ PARALLEL(t, 5) */ colC,
SUM (CASE WHEN colD > colE AND colE != '0' THEN colD / ColE END)de,
SUM (CASE WHEN colE > colD AND colD != '0' THEN colE / ColD END)ed,
SUM (CASE WHEN colD = colE AND colD != '0' THEN '1' END) de_one,
SUM (CASE WHEN colD = '0' OR colE = '0' THEN '0' END) de_zero
FROM TABLE (processor (base_query (argA, argB),100)) t
GROUP BY colC
ORDER BY colC
END with_pipeline;
PROCEDURE no_pipeline (argA IN VARCHAR2,
argB IN VARCHAR2,
o_resultset OUT resultset_typ)
IS
BEGIN
OPEN o_resultset FOR
SELECT colC,
SUM (CASE WHEN colD > colE AND colE != '0' THEN colD / ColE END)de,
SUM (CASE WHEN colE > colD AND colD != '0' THEN colE / ColD END)ed,
SUM (CASE WHEN colD = colE AND colD != '0' THEN 1 END) de_one,
SUM (CASE WHEN colD = '0' OR colE = '0' THEN '0' END) de_zero
FROM (SELECT colC, colD, colE
FROM some_table
WHERE colA = ArgA AND colB = argB)
GROUP BY colC
ORDER BY colC;
END no_pipeline;
END pipeline_example;
ALTER PACKAGE pipeline_example COMPILE;Edited by: Earthlink on Nov 14, 2010 9:47 AM
Edited by: Earthlink on Nov 14, 2010 11:31 AM
Edited by: Earthlink on Nov 14, 2010 11:32 AM
Edited by: Earthlink on Nov 20, 2010 12:04 PM
Edited by: Earthlink on Nov 20, 2010 12:54 PMEarthlink wrote:
Contrary to my understanding, the <font face="courier">with_pipeline</font> procedure runs 6 time slower than the legacy <font face="courier">no_pipeline</font> procedure. Am I missing something? Well, we're missing a lot here.
Like:
- a database version
- how did you test
- what data do you have, how is it distributed, indexed
and so on.
If you want to find out what's going on then use a TRACE with wait events.
All nessecary steps are explained in these threads:
HOW TO: Post a SQL statement tuning request - template posting
http://oracle-randolf.blogspot.com/2009/02/basic-sql-statement-performance.html
Another nice one is RUNSTATS:
http://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=6551378329289980701 -
Oracle 11g Table function returns no records on first call
Hello,
On a Oracle 11g R2 I've a table function ( PIPELINED ) returning rows selected from a table.
The first time the function is selected, in a session ( I've tried to disconnect and log in again ), it returns no rows.
I've tried to log the call using DBMS_OUTPUT and from what I see the select on the table function returns no rows and no output is printed. So I presume Oracle is not calling the function.
The same function on a similar environment ( same db versions, patches and database structure ) works fine. The second environment is a production environment so it has more memory and some other settings enabled.
Does anyone know of settings that can relate to this behaviour ?
Thanks in advance for the help.
Regards,
Stefano MuretThank you for answering so fast.
Here's the function code:
FUNCTION template_parameters (iTemplate IN TEMPLATE_RAW_DATA.TMPL_ID%TYPE := NULL)
RETURN table_type_tmpl_parameters PIPELINED
IS
li_exception INTEGER DEFAULT -20025;
POUT_PARM TABLE_TYPE_TMPL_PARAMETERS;
lt_parms table_type_tmpl_parms_raw;
sParmCheck VARCHAR2(4000);
iOccurrence INTEGER;
BEGIN
pOut_Parm := table_type_tmpl_parameters();
pOut_Parm.EXTEND;
select
tmpl_id
*,tmpl_name*
*,replace(upper(trim(sql_out)),'[SCHEMA].')*
*,UPPER(TRIM(out_tmpl_parms))*
bulk collect into lt_parms
from ref_templates
where tmpl_id = NVL(iTemplate,tmpl_id)
order by tmpl_id;
FOR k IN 1..lt_parms.COUNT
LOOP
pOut_Parm(1).tmpl_id := lt_parms(k).tmpl_id;
pOut_Parm(1).tmpl_name := lt_parms(k).tmpl_name;
FOR i IN 1..2
LOOP
IF i = 1 THEN
sParmCheck := lt_parms(k).sql_out;
ELSE
sParmCheck := lt_parms(k).sql_parms;
END IF;
iOccurrence := 1;
*pOut_Parm(1).parameter_name := regexp_substr(sParmCheck,'\[[^\[]+\]',1,iOccurrence);*
WHILE pOut_Parm(1).parameter_name IS NOT NULL
LOOP
PIPE ROW (pOut_Parm(1));
iOccurrence := iOccurrence + 1;
*pOut_Parm(1).parameter_name := regexp_substr(sParmCheck,'\[[^\[]+\]',1,iOccurrence);*
END LOOP;
END LOOP;
END LOOP;
RETURN;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(li_exception,SUBSTR(SQLERRM,1,1000));
RETURN;
END template_parameters;
This function is part of a package.
The data on both environments is the same. -
Question about Table Function inside a Package
Hi … I am new in PL/SQL, I am trying to use a table function to create depending on a value passed to it (I am using 10g). Everything works great but the moment I add a parameter everything explode, I am creating it on a package.
SQL that work
CREATE OR REPLACE PACKAGE BODY financial_reports AS
FUNCTION Fund_Amount
RETURN financial_reports.Fund_Amount_Table
pipelined parallel_enable IS
cur_row financial_reports.Fund_Amount_Record;
BEGIN
FOR cur_row IN
SELECT
to_number(substr(bu5.usrdata, 1, 1)) As SECTION_ID
,to_number(substr(bu5.usrdata, 2, 1)) As SUB_SECTION_ID
,to_number(substr(bu5.usrdata, 4, 2)) AS LINE_NUMBER
,to_number(substr(bu5.usrdata, 7, 2)) As FUND_ID
,sum(be.amt) AS AMOUNT
FROM
linc.budgetdb_usr5@stjohnsfp bu5
JOIN linc.budgetdb_event@stjohnsfp be ON
bu5.keyvalue = be.acctno
WHERE
bu5.keyvalue like '__-__-__-____-____-_____'
AND bu5.usrdata like '__-__-__'
AND bu5.fieldnum = 1
AND bu5.ispecname = 'GLMST'
AND to_number(substr(bu5.usrdata, 7, 2)) = 1
GROUP BY
bu5.usrdata
ORDER BY
bu5.usrdata
LOOP
PIPE ROW(cur_row);
END LOOP;
END Fund_Amount;
END financial_reports;
SQL that do not work …
CREATE OR REPLACE PACKAGE BODY financial_reports AS
FUNCTION Fund_Amount (Fund_Id IN NUMBER)
RETURN financial_reports.Fund_Amount_Table
pipelined parallel_enable IS
cur_row financial_reports.Fund_Amount_Record;
fund_id_int NUMBER;
BEGIN
fund_id_int := Fund_Id;
FOR cur_row IN
SELECT
to_number(substr(bu5.usrdata, 1, 1)) As SECTION_ID
,to_number(substr(bu5.usrdata, 2, 1)) As SUB_SECTION_ID
,to_number(substr(bu5.usrdata, 4, 2)) AS LINE_NUMBER
,to_number(substr(bu5.usrdata, 7, 2)) As FUND_ID
,sum(be.amt) AS AMOUNT
FROM
linc.budgetdb_usr5@stjohnsfp bu5
JOIN linc.budgetdb_event@stjohnsfp be ON
bu5.keyvalue = be.acctno
WHERE
bu5.keyvalue like '__-__-__-____-____-_____'
AND bu5.usrdata like '__-__-__'
AND bu5.fieldnum = 1
AND bu5.ispecname = 'GLMST'
AND to_number(substr(bu5.usrdata, 7, 2)) = fund_id_int
GROUP BY
bu5.usrdata
ORDER BY
bu5.usrdata
LOOP
PIPE ROW(cur_row);
END LOOP;
END Fund_Amount;
END financial_reports;
Error … (This works without the parameter)
Error starting at line 43 in command:
select * from table(financial_reports.Fund_Amount(1) )
Error at Command Line:1 Column:14
Error report:
SQL Error: ORA-22905: cannot access rows from a non-nested table item
Any help would be greatly appreciatedtry renaming your parameter so as not to confuse with what you are using in your column " to_number(substr(bu5.usrdata, 7, 2)) AS FUND_ID":
CREATE OR REPLACE PACKAGE BODY financial_reports AS
FUNCTION Fund_Amount (pFund_Id IN NUMBER)
RETURN financial_reports.Fund_Amount_Table
pipelined parallel_enable IS
cur_row financial_reports.Fund_Amount_Record;
fund_id_int NUMBER;
BEGIN
fund_id_int := pFund_Id;
FOR cur_row IN ( SELECT to_number(substr(bu5.usrdata, 1, 1)) As SECTION_ID,
to_number(substr(bu5.usrdata, 2, 1)) As SUB_SECTION_ID,
to_number(substr(bu5.usrdata, 4, 2)) AS LINE_NUMBER,
to_number(substr(bu5.usrdata, 7, 2)) As FUND_ID,
sum(be.amt) AS AMOUNT
FROM linc.budgetdb_usr5@stjohnsfp bu5
JOIN linc.budgetdb_event@stjohnsfp be ON bu5.keyvalue = be.acctno
WHERE bu5.keyvalue like '__-__-__-____-____-_____'
AND bu5.usrdata like '__-__-__'
AND bu5.fieldnum = 1
AND bu5.ispecname = 'GLMST'
AND to_number(substr(bu5.usrdata, 7, 2)) = fund_id_int
GROUP BY bu5.usrdata
ORDER BY bu5.usrdata ) LOOP
PIPE ROW(cur_row);
END LOOP;
END Fund_Amount;
END financial_reports; -
Parallel not working in pipelined table function?
I've found this excelent article titled 'Oracle fast parallel data unload into ASCII file(s)' in this blog: http://jiri.wordpress.com/2009/03/18/oracle-fast-parallel-data-unload-into-ascii-files/
I have compiled the code and created the objects and the directory in my DB
But when I execute :
SELECT *
FROM TABLE(
DATA_UNLOAD(
CURSOR(
SELECT /*+ PARALLEL(A, 2, 1) */
TABLE_NAME || '|' ||
COLUMN_NAME || '|' ||
DATA_TYPE
FROM MYTABLE A
'SAMPLE_SPOOL.TXT',
'DIR_USERS_JIRI',
'Y',
'Y' )
It is suposed to return 2 rows (because of parallel execution), but it just returns 1
Do I have to do something special in order to make parallel pipelined function work
Edited by: igorcb123 on 01-02-2011 01:58 PMIf & Else is wrongly used in the function
FUNCTION F_PS_HIGH_SCHOOL (OLD_HS CHAR)
RETURN
CHAR
IS
NEW_HIGH_SCHOOL CHAR(11);
BEGIN
IF OLD_HS = ' ' THEN NEW_HIGH_SCHOOL := ' ';
ELSE-- Incorrect usage
SELECT
MC_AD_HS_NAME INTO NEW_HIGH_SCHOOL
FROM
XLAT_HIGH_SCHOOL_CODES_2
WHERE
SIS_HS_CODE = OLD_HS;
RETURN NEW_HIGH_SCHOOL;
END IF;
RETURN NEW_HIGH_SCHOOL;
END F_PS_HIGH_SCHOOL; -
10g: delay for collecting results from parallel pipelined table functions
When parallel pipelined table functions are properly started and generate output record, there is a delay for the consuming main thread to gather these records.
This delay is huge compared with the run-time of the worker threads.
For my application it goes like this:
main thread timing efforts to start worker and collect their results:
[10:50:33-*10:50:49*]:JOMA: create (master): 015.93 sec (#66356 records, #4165/sec)
worker threads:
[10:50:34-*10:50:39*]:JOMA: create (slave) : 005.24 sec (#2449 EDRs, #467/sec, #0 errored / #6430 EBTMs, #1227/sec, #0 errored) - bulk #1 / sid #816
[10:50:34-*10:50:39*]:JOMA: create (slave) : 005.56 sec (#2543 EDRs, #457/sec, #0 errored / #6792 EBTMs, #1221/sec, #0 errored) - bulk #1 / sid #718
[10:50:34-*10:50:39*]:JOMA: create (slave) : 005.69 sec (#2610 EDRs, #459/sec, #0 errored / #6950 EBTMs, #1221/sec, #0 errored) - bulk #1 / sid #614
[10:50:34-*10:50:39*]:JOMA: create (slave) : 005.55 sec (#2548 EDRs, #459/sec, #0 errored / #6744 EBTMs, #1216/sec, #0 errored) - bulk #1 / sid #590
[10:50:34-*10:50:39*]:JOMA: create (slave) : 005.33 sec (#2461 EDRs, #462/sec, #0 errored / #6504 EBTMs, #1220/sec, #0 errored) - bulk #1 / sid #508
You can see, the worker threads are all started at the same time and terminating at the same time: 10:50:34-10:50:*39*.
But the main thread just invoking them and saving their results into a collection has finished at 10:50:*49*.
Why does it need #10 sec more just to save the data?
Here's a sample sqlplus script to demonstrate this:
--------------------------- snip -------------------------------------------------------
set serveroutput on;
drop table perf_data;
drop table test_table;
drop table tmp_test_table;
drop type ton_t;
drop type test_list;
drop type test_obj;
create table perf_data
sid number,
t1 timestamp with time zone,
t2 timestamp with time zone,
client varchar2(256)
create table test_table
a number(19,0),
b timestamp with time zone,
c varchar2(256)
create global temporary table tmp_test_table
a number(19,0),
b timestamp with time zone,
c varchar2(256)
create or replace type test_obj as object(
a number(19,0),
b timestamp with time zone,
c varchar2(256)
create or replace type test_list as table of test_obj;
create or replace type ton_t as table of number;
create or replace package test_pkg
as
type test_rec is record (
a number(19,0),
b timestamp with time zone,
c varchar2(256)
type test_tab is table of test_rec;
type test_cur is ref cursor return test_rec;
function TZDeltaToMilliseconds(
t1 in timestamp with time zone,
t2 in timestamp with time zone)
return pls_integer;
function TF(mycur test_cur)
return test_list pipelined
parallel_enable(partition mycur by hash(a));
end;
create or replace package body test_pkg
as
* Calculate timestamp with timezone difference
* in milliseconds
function TZDeltaToMilliseconds(
t1 in timestamp with time zone,
t2 in timestamp with time zone)
return pls_integer
is
begin
return (extract(hour from t2) - extract(hour from t1)) * 3600 * 1000
+ (extract(minute from t2) - extract(minute from t1)) * 60 * 1000
+ (extract(second from t2) - extract(second from t1)) * 1000;
end TZDeltaToMilliseconds;
function TF(mycur test_cur)
return test_list pipelined
parallel_enable(partition mycur by hash(a))
is
pragma autonomous_transaction;
sid number;
counter number(19,0) := 0;
myrec test_rec;
mytab test_tab;
mytab2 test_list := test_list();
t1 timestamp with time zone;
t2 timestamp with time zone;
begin
t1 := systimestamp;
select userenv('SID') into sid from dual;
dbms_output.put_line('test_pkg.TF( sid => '''|| sid || ''' ): enter');
loop
fetch mycur into myRec;
exit when mycur%NOTFOUND;
mytab2.extend;
mytab2(mytab2.last) := test_obj(myRec.a, myRec.b, myRec.c);
end loop;
for i in mytab2.first..mytab2.last loop
-- attention: saves own SID in test_obj.a for indication to caller
-- how many sids have been involved
pipe row(test_obj(sid, mytab2(i).b, mytab2(i).c));
pipe row(test_obj(sid, mytab2(i).b, mytab2(i).c)); -- duplicate
pipe row(test_obj(sid, mytab2(i).b, mytab2(i).c)); -- duplicate once again
counter := counter + 1;
end loop;
t2 := systimestamp;
insert into perf_data (sid, t1, t2, client) values(sid, t1, t2, 'slave');
commit;
dbms_output.put_line('test_pkg.TF( sid => '''|| sid || ''' ): exit, piped #' || counter || ' records');
end;
end;
declare
myList test_list := test_list();
myList2 test_list := test_list();
sids ton_t := ton_t();
sid number;
t1 timestamp with time zone;
t2 timestamp with time zone;
procedure LogPerfTable
is
type ton is table of number;
type tot is table of timestamp with time zone;
type clients_t is table of varchar2(256);
sids ton;
t1s tot;
t2s tot;
clients clients_t;
deltaTime integer;
btsPerSecond number(19,0);
edrsPerSecond number(19,0);
begin
select sid, t1, t2, client bulk collect into sids, t1s, t2s, clients from perf_data order by client;
if clients.count > 0 then
for i in clients.FIRST .. clients.LAST loop
deltaTime := test_pkg.TZDeltaToMilliseconds(t1s(i), t2s(i));
if deltaTime = 0 then deltaTime := 1; end if;
dbms_output.put_line(
'[' || to_char(t1s(i), 'hh:mi:ss') ||
'-' || to_char(t2s(i), 'hh:mi:ss') ||
']:' ||
' client ' || clients(i) || ' / sid #' || sids(i)
end loop;
end if;
end LogPerfTable;
begin
select userenv('SID') into sid from dual;
for i in 1..200000 loop
myList.extend; myList(myList.last) := test_obj(i, sysdate, to_char(i+2));
end loop;
-- save into the real table
insert into test_table select * from table(cast (myList as test_list));
-- save into the tmp table
insert into tmp_test_table select * from table(cast (myList as test_list));
dbms_output.put_line(chr(10) || '(1) copy ''mylist'' to ''mylist2'' by streaming via table function...');
delete from perf_data;
t1 := systimestamp;
select /*+ first_rows */ test_obj(a, b, c) bulk collect into myList2
from table(test_pkg.TF(CURSOR(select /*+ parallel(tab,5) */ * from table(cast (myList as test_list)) tab)));
t2 := systimestamp;
insert into perf_data (sid, t1, t2, client) values(sid, t1, t2, 'master');
LogPerfTable;
dbms_output.put_line('... saved #' || myList2.count || ' records');
select distinct(tab.a) bulk collect into sids from table(cast (myList2 as test_list)) tab;
dbms_output.put_line(chr(10) || '(2) copy temporary ''tmp_test_table'' to ''mylist2'' by streaming via table function:');
delete from perf_data;
t1 := systimestamp;
select /*+ first_rows */ test_obj(a, b, c) bulk collect into myList2
from table(test_pkg.TF(CURSOR(select /*+ parallel(tab,5) */ * from tmp_test_table tab)));
t2 := systimestamp;
insert into perf_data (sid, t1, t2, client) values(sid, t1, t2, 'master');
LogPerfTable;
dbms_output.put_line('... saved #' || myList2.count || ' records');
select distinct(tab.a) bulk collect into sids from table(cast (myList2 as test_list)) tab;
dbms_output.put_line(chr(10) || '(3) copy physical ''test_table'' to ''mylist2'' by streaming via table function:');
delete from perf_data;
t1 := systimestamp;
select /*+ first_rows */ test_obj(a, b, c) bulk collect into myList2
from table(test_pkg.TF(CURSOR(select /*+ parallel(tab,5) */ * from test_table tab)));
t2 := systimestamp;
insert into perf_data (sid, t1, t2, client) values(sid, t1, t2, 'master');
LogPerfTable;
dbms_output.put_line('... saved #' || myList2.count || ' records');
select distinct(tab.a) bulk collect into sids from table(cast (myList2 as test_list)) tab;
end;
--------------------------- snap -------------------------------------------------------
best regards,
FrankHello
I think the delay you are seeing is down to choosing the partitioning method as HASH. When you specify anything other than ANY, an additional buffer sort is included in the execution plan...
create or replace package test_pkg
as
type test_rec is record (
a number(19,0),
b timestamp with time zone,
c varchar2(256)
type test_tab is table of test_rec;
type test_cur is ref cursor return test_rec;
function TZDeltaToMilliseconds(
t1 in timestamp with time zone,
t2 in timestamp with time zone)
return pls_integer;
function TF(mycur test_cur)
return test_list pipelined
parallel_enable(partition mycur by hash(a));
function TF_Any(mycur test_cur)
return test_list pipelined
parallel_enable(partition mycur by ANY);
end;
create or replace package body test_pkg
as
* Calculate timestamp with timezone difference
* in milliseconds
function TZDeltaToMilliseconds(
t1 in timestamp with time zone,
t2 in timestamp with time zone)
return pls_integer
is
begin
return (extract(hour from t2) - extract(hour from t1)) * 3600 * 1000
+ (extract(minute from t2) - extract(minute from t1)) * 60 * 1000
+ (extract(second from t2) - extract(second from t1)) * 1000;
end TZDeltaToMilliseconds;
function TF(mycur test_cur)
return test_list pipelined
parallel_enable(partition mycur by hash(a))
is
pragma autonomous_transaction;
sid number;
counter number(19,0) := 0;
myrec test_rec;
t1 timestamp with time zone;
t2 timestamp with time zone;
begin
t1 := systimestamp;
select userenv('SID') into sid from dual;
dbms_output.put_line('test_pkg.TF( sid => '''|| sid || ''' ): enter');
loop
fetch mycur into myRec;
exit when mycur%NOTFOUND;
-- attention: saves own SID in test_obj.a for indication to caller
-- how many sids have been involved
pipe row(test_obj(sid, myRec.b, myRec.c));
pipe row(test_obj(sid, myRec.b, myRec.c)); -- duplicate
pipe row(test_obj(sid, myRec.b, myRec.c)); -- duplicate once again
counter := counter + 1;
end loop;
t2 := systimestamp;
insert into perf_data (sid, t1, t2, client) values(sid, t1, t2, 'slave');
commit;
dbms_output.put_line('test_pkg.TF( sid => '''|| sid || ''' ): exit, piped #' || counter || ' records');
end;
function TF_any(mycur test_cur)
return test_list pipelined
parallel_enable(partition mycur by ANY)
is
pragma autonomous_transaction;
sid number;
counter number(19,0) := 0;
myrec test_rec;
t1 timestamp with time zone;
t2 timestamp with time zone;
begin
t1 := systimestamp;
select userenv('SID') into sid from dual;
dbms_output.put_line('test_pkg.TF( sid => '''|| sid || ''' ): enter');
loop
fetch mycur into myRec;
exit when mycur%NOTFOUND;
-- attention: saves own SID in test_obj.a for indication to caller
-- how many sids have been involved
pipe row(test_obj(sid, myRec.b, myRec.c));
pipe row(test_obj(sid, myRec.b, myRec.c)); -- duplicate
pipe row(test_obj(sid, myRec.b, myRec.c)); -- duplicate once again
counter := counter + 1;
end loop;
t2 := systimestamp;
insert into perf_data (sid, t1, t2, client) values(sid, t1, t2, 'slave');
commit;
dbms_output.put_line('test_pkg.TF( sid => '''|| sid || ''' ): exit, piped #' || counter || ' records');
end;
end;
explain plan for
select /*+ first_rows */ test_obj(a, b, c)
from table(test_pkg.TF(CURSOR(select /*+ parallel(tab,5) */ * from test_table tab)));
select * from table(dbms_xplan.display);
Plan hash value: 1037943675
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
| 0 | SELECT STATEMENT | | 8168 | 3972K| 20 (0)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10001 | 8168 | 3972K| 20 (0)| 00:00:01 | Q1,01 | P->S | QC (RAND) |
| 3 | BUFFER SORT | | 8168 | 3972K| | | Q1,01 | PCWP | |
| 4 | VIEW | | 8168 | 3972K| 20 (0)| 00:00:01 | Q1,01 | PCWP | |
| 5 | COLLECTION ITERATOR PICKLER FETCH| TF | | | | | Q1,01 | PCWP | |
| 6 | PX RECEIVE | | 931K| 140M| 136 (2)| 00:00:02 | Q1,01 | PCWP | |
| 7 | PX SEND HASH | :TQ10000 | 931K| 140M| 136 (2)| 00:00:02 | Q1,00 | P->P | HASH |
| 8 | PX BLOCK ITERATOR | | 931K| 140M| 136 (2)| 00:00:02 | Q1,00 | PCWC | |
| 9 | TABLE ACCESS FULL | TEST_TABLE | 931K| 140M| 136 (2)| 00:00:02 | Q1,00 | PCWP | |
Note
- dynamic sampling used for this statement
explain plan for
select /*+ first_rows */ test_obj(a, b, c)
from table(test_pkg.TF_Any(CURSOR(select /*+ parallel(tab,5) */ * from test_table tab)));
select * from table(dbms_xplan.display);
Plan hash value: 4097140875
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
| 0 | SELECT STATEMENT | | 8168 | 3972K| 20 (0)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10000 | 8168 | 3972K| 20 (0)| 00:00:01 | Q1,00 | P->S | QC (RAND) |
| 3 | VIEW | | 8168 | 3972K| 20 (0)| 00:00:01 | Q1,00 | PCWP | |
| 4 | COLLECTION ITERATOR PICKLER FETCH| TF_ANY | | | | | Q1,00 | PCWP | |
| 5 | PX BLOCK ITERATOR | | 931K| 140M| 136 (2)| 00:00:02 | Q1,00 | PCWC | |
| 6 | TABLE ACCESS FULL | TEST_TABLE | 931K| 140M| 136 (2)| 00:00:02 | Q1,00 | PCWP | |
Note
- dynamic sampling used for this statementI posted about it here a few years ago and I more recently posted a question on Asktom. Unfortunately Tom was not able to find a technical reason for it to be there so I'm still a little in the dark as to why it is needed. The original question I posted is here:
Pipelined function partition by hash has extra sort#
I ran your tests with HASH vs ANY and the results are in line with the observations above....
declare
myList test_list := test_list();
myList2 test_list := test_list();
sids ton_t := ton_t();
sid number;
t1 timestamp with time zone;
t2 timestamp with time zone;
procedure LogPerfTable
is
type ton is table of number;
type tot is table of timestamp with time zone;
type clients_t is table of varchar2(256);
sids ton;
t1s tot;
t2s tot;
clients clients_t;
deltaTime integer;
btsPerSecond number(19,0);
edrsPerSecond number(19,0);
begin
select sid, t1, t2, client bulk collect into sids, t1s, t2s, clients from perf_data order by client;
if clients.count > 0 then
for i in clients.FIRST .. clients.LAST loop
deltaTime := test_pkg.TZDeltaToMilliseconds(t1s(i), t2s(i));
if deltaTime = 0 then deltaTime := 1; end if;
dbms_output.put_line(
'[' || to_char(t1s(i), 'hh:mi:ss') ||
'-' || to_char(t2s(i), 'hh:mi:ss') ||
']:' ||
' client ' || clients(i) || ' / sid #' || sids(i)
end loop;
end if;
end LogPerfTable;
begin
select userenv('SID') into sid from dual;
for i in 1..200000 loop
myList.extend; myList(myList.last) := test_obj(i, sysdate, to_char(i+2));
end loop;
-- save into the real table
insert into test_table select * from table(cast (myList as test_list));
-- save into the tmp table
insert into tmp_test_table select * from table(cast (myList as test_list));
dbms_output.put_line(chr(10) || '(1) copy ''mylist'' to ''mylist2'' by streaming via table function...');
delete from perf_data;
t1 := systimestamp;
select /*+ first_rows */ test_obj(a, b, c) bulk collect into myList2
from table(test_pkg.TF(CURSOR(select /*+ parallel(tab,5) */ * from table(cast (myList as test_list)) tab)));
t2 := systimestamp;
insert into perf_data (sid, t1, t2, client) values(sid, t1, t2, 'master');
LogPerfTable;
dbms_output.put_line('... saved #' || myList2.count || ' records');
select distinct(tab.a) bulk collect into sids from table(cast (myList2 as test_list)) tab;
dbms_output.put_line(chr(10) || '(2) copy temporary ''tmp_test_table'' to ''mylist2'' by streaming via table function:');
delete from perf_data;
t1 := systimestamp;
select /*+ first_rows */ test_obj(a, b, c) bulk collect into myList2
from table(test_pkg.TF(CURSOR(select /*+ parallel(tab,5) */ * from tmp_test_table tab)));
t2 := systimestamp;
insert into perf_data (sid, t1, t2, client) values(sid, t1, t2, 'master');
LogPerfTable;
dbms_output.put_line('... saved #' || myList2.count || ' records');
select distinct(tab.a) bulk collect into sids from table(cast (myList2 as test_list)) tab;
dbms_output.put_line(chr(10) || '(3) copy physical ''test_table'' to ''mylist2'' by streaming via table function:');
delete from perf_data;
t1 := systimestamp;
select /*+ first_rows */ test_obj(a, b, c) bulk collect into myList2
from table(test_pkg.TF(CURSOR(select /*+ parallel(tab,5) */ * from test_table tab)));
t2 := systimestamp;
insert into perf_data (sid, t1, t2, client) values(sid, t1, t2, 'master');
LogPerfTable;
dbms_output.put_line('... saved #' || myList2.count || ' records');
select distinct(tab.a) bulk collect into sids from table(cast (myList2 as test_list)) tab;
dbms_output.put_line(chr(10) || '(4) copy temporary ''tmp_test_table'' to ''mylist2'' by streaming via table function ANY:');
delete from perf_data;
t1 := systimestamp;
select /*+ first_rows */ test_obj(a, b, c) bulk collect into myList2
from table(test_pkg.TF_any(CURSOR(select /*+ parallel(tab,5) */ * from tmp_test_table tab)));
t2 := systimestamp;
insert into perf_data (sid, t1, t2, client) values(sid, t1, t2, 'master');
LogPerfTable;
dbms_output.put_line('... saved #' || myList2.count || ' records');
select distinct(tab.a) bulk collect into sids from table(cast (myList2 as test_list)) tab;
dbms_output.put_line(chr(10) || '(5) copy physical ''test_table'' to ''mylist2'' by streaming via table function using ANY:');
delete from perf_data;
t1 := systimestamp;
select /*+ first_rows */ test_obj(a, b, c) bulk collect into myList2
from table(test_pkg.TF_any(CURSOR(select /*+ parallel(tab,5) */ * from test_table tab)));
t2 := systimestamp;
insert into perf_data (sid, t1, t2, client) values(sid, t1, t2, 'master');
LogPerfTable;
dbms_output.put_line('... saved #' || myList2.count || ' records');
select distinct(tab.a) bulk collect into sids from table(cast (myList2 as test_list)) tab;
end;
(1) copy 'mylist' to 'mylist2' by streaming via table function...
test_pkg.TF( sid => '918' ): enter
test_pkg.TF( sid => '918' ): exit, piped #200000 records
[01:40:19-01:40:29]: client master / sid #918
[01:40:19-01:40:29]: client slave / sid #918
... saved #600000 records
(2) copy temporary 'tmp_test_table' to 'mylist2' by streaming via table function:
[01:40:31-01:40:36]: client master / sid #918
[01:40:31-01:40:32]: client slave / sid #659
[01:40:31-01:40:32]: client slave / sid #880
[01:40:31-01:40:32]: client slave / sid #1045
[01:40:31-01:40:32]: client slave / sid #963
[01:40:31-01:40:32]: client slave / sid #712
... saved #600000 records
(3) copy physical 'test_table' to 'mylist2' by streaming via table function:
[01:40:37-01:41:05]: client master / sid #918
[01:40:37-01:40:42]: client slave / sid #738
[01:40:37-01:40:42]: client slave / sid #568
[01:40:37-01:40:42]: client slave / sid #618
[01:40:37-01:40:42]: client slave / sid #659
[01:40:37-01:40:42]: client slave / sid #963
... saved #3000000 records
(4) copy temporary 'tmp_test_table' to 'mylist2' by streaming via table function ANY:
[01:41:12-01:41:16]: client master / sid #918
[01:41:12-01:41:16]: client slave / sid #712
[01:41:12-01:41:16]: client slave / sid #1045
[01:41:12-01:41:16]: client slave / sid #681
[01:41:12-01:41:16]: client slave / sid #754
[01:41:12-01:41:16]: client slave / sid #880
... saved #600000 records
(5) copy physical 'test_table' to 'mylist2' by streaming via table function using ANY:
[01:41:18-01:41:38]: client master / sid #918
[01:41:18-01:41:38]: client slave / sid #681
[01:41:18-01:41:38]: client slave / sid #712
[01:41:18-01:41:38]: client slave / sid #754
[01:41:18-01:41:37]: client slave / sid #880
[01:41:18-01:41:38]: client slave / sid #1045
... saved #3000000 recordsHTH
David -
Ora-600 using table function over db link
Hi,
I have a table function n my target schema (OWB 9.2.0.4 on Oracle 9.2.0.5) with the following signature:
function uii_get_exchange_data_tf(
p_input_values in sys_refcursor
) return uii_exchange_table_t pipelined
When I try to use this with a remote table over a db link, e.g.:
=============
select * from table(uii_get_exchange_data_tf(cursor (select sub_zone || '/' || exch_grp_cd exchange_id,
exch_name exchange_name FROM cds_exchange_test@uiid1@uiidraconn order by exchange_id)))
==============
I get this:
================
ORA-00600: internal error code, arguments: [kokbnp2], [942], [], [], [], [], [],
ORA-06512: at "UII_ODS_OWNER_DEV.UII_GET_EXCHANGE_DATA_TF", line 21
=================
However, if I create a local view with the same remote select like this:
===================
CREATE OR REPLACE FORCE VIEW UII_CDS_EXCHANGE_RV
AS SELECT sub_zone || '/' || exch_grp_cd exchange_id,
exch_name exchange_name
FROM cds_css_exch_detail@uiid1@uiidraconn;
====================
Then everything works fine.
Can someone help ? I'm sure I'm dooing something silly, since so many people seem to be using table functions from OWB just fine; but I can't figure out what :-(
Thanks in advance.
Regards,
Biswa.Hello,
Is this query works fine without creating mview
SELECT COL1,COL2, CASE when COL3 = Y then (select X from MASTER2@DBLINK) FROM MASTER1@DBLINK.
try something like this
SELECT col1, col2, CASE
WHEN col3 = y
THEN
(SELECT x
FROM master2@dblink)
END
my
FROM master1@dblinkregards -
Transfer Order number in MSEG table
Hi,
I am a Technical team member and while preparing Technical Specification for a Report I came accross a problem that when we do a PGI the Transfer Order field in the table MSEG does not get updated.
My requirement is to get the Transfer Order number from the Material document, and I don't understand why this field isn't getting updated in MSEG table with reference Transfer order when one does a PGI.
Please let me know if there is any configuration I need to check with so that I can go with this info to my Functional team.
Appreciate your help in this regard.
Thanks and Regards,
Saleem.Hi Saleem
In MSEG you can find TR number (MSEG-TBNUM). Take MBLNR from MSEG and pass into LTAK table. There you can find TO Number (LTAK-TANUM)
Hope it helps
regards
Srinivas
reward if it is useful -
Hi,
1 . what is table()?
2. Can you please explain the below line of code?
PROCEDURE ins_alias (
pv_app_o OUT t$app.app%TYPE,
pv_name_i IN t$app.name%TYPE,
pva_apps_i IN id_vt
AS
lv_app t$app.app%TYPE;
lv_userid t$app.userid%TYPE;
lva_new_apps t$app.apps%TYPE;
BEGIN
-- Only add valid apps (ones that exist and are not user-created)
SELECT t1.COLUMN_VALUE BULK COLLECT INTO lva_new_apps
FROM TABLE (pva_apps_i) t1
WHERE EXISTS
(SELECT 1
FROM t$app a1
WHERE a1.app = t1.column_value AND
a1.userid IS NULL)
ORDER BY COLUMN_VALUE;
what is column_value and table() in the code?
Thanks,table() takes a certain sort of parameter and turns it into a table that can be queried.
Such parameters may be Pipelined Functions, or certain types of collections/arrays.
So, in your example:
pva_apps_i is of a type id_vt, which I'm guessing is some sort of collection type (sql table type).
COLUMN_VALUE is the default name given to a TABLE() function's returned column, if there is only one column returned, indicating your collection is a simple array with just a list of values.
It's possible to create a collection of object types and have the table function return the column names as the names of the attributes of the object, such as the following example which uses a pipelined function...
CREATE OR REPLACE TYPE myrec AS OBJECT
( col1 VARCHAR2(10),
col2 VARCHAR2(10)
CREATE OR REPLACE TYPE myrectable AS TABLE OF myrec
CREATE OR REPLACE FUNCTION pipedata(p_str IN VARCHAR2) RETURN myrectable PIPELINED IS
v_str VARCHAR2(4000) := REPLACE(REPLACE(p_str, '('),')');
v_obj myrec := myrec(NULL,NULL);
BEGIN
LOOP
EXIT WHEN v_str IS NULL;
v_obj.col1 := SUBSTR(v_str,1,INSTR(v_str,',')-1);
v_str := SUBSTR(v_str,INSTR(v_str,',')+1);
IF INSTR(v_str,',')>0 THEN
v_obj.col2 := SUBSTR(v_str,1,INSTR(v_str,',')-1);
v_str := SUBSTR(v_str,INSTR(v_str,',')+1);
ELSE
v_obj.col2 := v_str;
v_str := NULL;
END IF;
PIPE ROW (v_obj);
END LOOP;
RETURN;
END;
SQL> select *
2 from table(pipedata('(1,2),(3,4),(5,6)'));
COL1 COL2
1 2
3 4
5 6 -
How to use the Table Function defined in package in OWB?
Hi,
I defined a table function in a package. I am trying to use that in owb using Table function operator. But I came to know that, owb R1 supports only standalone table functions.
Is there any other way to use the table function defined in a package. As like we create synonyms for functions, is there any other way to do this.
I tryed to create synonyms, it is created. But it is showing compilation error. Finally I found that, we can't create synonyms for functions which are defined in packages.
Any one can explain it, how to resolve this problem.
Thank you,
Regards
Gowtham Sen.Hi Marcos,
Thank you for reply.
OWB R1 supports stand alone table functions. Here what I mean is, the table fucntion which is not inculded in any package is a stand alone table function.
for example say sample_tbl_fn is a table function. It is defined as a function.It is a stand alone function. We call this fucntion as "samp_tbl_fn()";
For exampe say sample_pkg is a package. say a function is defined in a package.
then we call that function as sample_pkg.functionname(); This is not a stand alone function.
I hope you understand it.
owb supports stand alone functions.
Here I would like to know, is there any other way to use the functions which are defined in package. While I am trying to use those functions (which are defined in package -- giving the name as packagename.functionname) it is throwing an error "Invalid object name."
Here I would like know, is there any other way to use the table functions which are defined in a package.
Thank you,
Regards,
Gowtham Sen. -
Table function on a collection in Dynamic SQL
Hello,
I am trying to create a refcursor by selecting from a collection using table function.
If I use the Select statement the query executes, but if I put the Select statement in a string
the collection variable does not get resolved. The resaon I am putiing it in a string is because the
WHERE clause will be passed a parameter. The code below is an anonymous block but will be changed to a
procedure once I get it to work.
I have tried many different ways but was unsuccessful.
Please see if anybody cann assist or what I am trying to achive is not possible, so provide an alternative.
The error I am getting is
ORA-00904: "V_ALARM_REC_TABLE": invalid identifier
ORA-06512: at line 50
Thanks.
Bimal
DECLARE
TYPE c_refcurtype IS REF CURSOR;
x c_refcurtype;
p_recordset c_refcurtype;
v_rec mc2_dev2.mc2_alarm_rec_type := mc2_dev2.mc2_alarm_rec_type(null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null);
v_alarm_rec_table mc2_dev2.mc2_alarm_rec_table := mc2_dev2.mc2_alarm_rec_table();
v_select varchar2(200) := 'select a.* from ';
v_table varchar2(200) := 'table(v_alarm_rec_table) a ';
v_where varchar2(200) := 'where a.alarm_rule_def_uid = 9';
v_query varchar2(32000);
BEGIN
MC2_ALARM.create_mc2_alarm(x, 1); --- ( X is a refcursor, which I will use to populate v_alarm_rec_table a (nested table collection)
LOOP
FETCH x INTO v_rec.record_cnt,
v_rec.rn,
v_rec.alarm_precision_order,
v_rec.alarm_rule_def_uid,
v_rec.alarm_type_def_uid,
v_rec.alarm_rule_scope_uid,
v_rec.trigger_tpl_master_uid,
v_rec.alarm_scope_def_uid,
v_rec.alarm_object_uid,
v_rec.error_type,
v_rec.all_error_codes,
v_rec.enabled,
v_rec.start_hour,
v_rec.end_hour,
v_rec.day_type,
v_rec.alarm_severity_def_uid,
v_rec.on_watch_duration,
v_rec.update_on_status_change,
v_rec.log_ind,
v_rec.email_to,
v_rec.email_from,
v_rec.send_email,
v_rec.stale_period;
EXIT WHEN x%NOTFOUND;
v_alarm_rec_table.extend;
v_alarm_rec_table(v_alarm_rec_table.last) := v_rec;
END LOOP;
CLOSE x;
v_query := v_select||v_table||v_where; -- ERROR OCCURS AT THIS LINE as it cannot resolve the TABLE name v_alarm_rec_table)
dbms_output.put_line('sql: '||v_query);
OPEN p_recordset FOR v_query;
LOOP
FETCH p_recordset INTO v_rec.record_cnt,
v_rec.rn,
v_rec.alarm_precision_order,
v_rec.alarm_rule_def_uid,
v_rec.alarm_type_def_uid,
v_rec.alarm_rule_scope_uid,
v_rec.trigger_tpl_master_uid,
v_rec.alarm_scope_def_uid,
v_rec.alarm_object_uid,
v_rec.error_type,
v_rec.all_error_codes,
v_rec.enabled,
v_rec.start_hour,
v_rec.end_hour,
v_rec.day_type,
v_rec.alarm_severity_def_uid,
v_rec.on_watch_duration,
v_rec.update_on_status_change,
v_rec.log_ind,
v_rec.email_to,
v_rec.email_from,
v_rec.send_email,
v_rec.stale_period;
EXIT WHEN p_recordset%NOTFOUND;
some dbms_output statements...
END LOOP;
END;
The error I am getting is
ORA-00904: "V_ALARM_REC_TABLE": invalid identifier
ORA-06512: at line 50Thanks Timur/Solomon,
mc2_dev2 is the schema name.
mc2_alarm_rec_table is a SQL type.
Here are the scripts:
CREATE OR REPLACE TYPE MC2_DEV2.mc2_alarm_rec_type IS OBJECT
( record_cnt NUMBER,
rn number,
alarm_precision_order NUMBER(6),
alarm_rule_def_uid NUMBER(6),
alarm_type_def_uid NUMBER(6),
alarm_rule_scope_uid NUMBER(6),
trigger_tpl_master_uid NUMBER(6),
alarm_scope_def_uid NUMBER(6),
alarm_object_uid NUMBER(6),
error_type VARCHAR2(1),
all_error_codes VARCHAR2(1),
enabled VARCHAR2(1),
start_hour NUMBER(2),
end_hour NUMBER(2),
day_type NUMBER(2),
alarm_severity_def_uid NUMBER(6),
on_watch_duration NUMBER(6),
update_on_status_change VARCHAR2(1),
log_ind VARCHAR2(1),
email_to VARCHAR2(128),
email_from VARCHAR2(128),
send_email VARCHAR2(1),
stale_period NUMBER(6)
CREATE OR REPLACE TYPE MC2_DEV2.MC2_ALARM_REC_TABLE IS TABLE OF MC2_DEV2.mc2_alarm_rec_type;
If I popoulate the cursor with the following code:
OPEN p_recordset FOR
select a.* from table (v_alarm_rec_table) a where a.alarm_rule_def_uid = 9;
there is no issue it works just fine.
But when when I use
OPEN p_recordset FOR v_query; ---- where v_query := v_select||v_table||v_where;
the variable v_alarm_rec_table does not get resolved.
Regards,
Bimal -
Interactive report on view based on pipelined table function.
Hi,
I want to build an Interactive Report on a view.
The view definition contains a select on a pipelined table function. I use context functionality to pass paramaters to the pipelined table function.
A plain select * from #my_view# in SqlPlus results in 121 different rows.
However, If I base my Interactive report on this view, I get 15 repeated rows (all the same).
Is it possible to use pipelined table functionality on an Interactive report? I can't seem to get it working.
If I use the following approach (http://rakeshjsr.blogspot.nl/2010/10/oracle-apex-interactive-report-based-on.html) I do get results, but I can't use this solution for a reason that's not relevant.Hello,
Is it possible to use pipelined table functionality on an Interactive report? I can't seem to get it working. I have used it in one instance and it works fine. However I was passing the values to pipe-lined function directly.
IR Query..
SELECT * FROM TABLE(fn_pipeline(:P1_ITEM_NAME))Call pipe-lined function from IR query directly (instead of using view)
Try sending values to Pipe-lined function directly. In-case if the problem is with setting and getting values from the context?
Regards,
Hari -
Drop default constraint on a table function
I need to drop some default constraints that appear to be tied to table functions (and not actual tables). This means when I try the ALTER TABLE DROP CONSTRAINT command it fails with the error, "unable to drop constraint because object is not
a table" or something similar.
My question is: how do I drop a constraint on a table function?I suggest you review the documentation for TVFs and how they are (and can be) used. The table returned by a TVF (and in this case I refer specifically to multistatement TVFs) are defined using a subset of the create table syntax. They can be
created with constraints of different types - not just defaults. Why? Because it suits the logic of the developer and (perhaps) because it assists the database engine or the logic that depends on the output of the function.
Below is one example that I used (written by Steve Kass) from a LONG time ago. Notice the primary key.
CREATE FUNCTION [dbo].[uf_sequence] (@N int)
RETURNS @T TABLE (
seq int not null primary key clustered
AS
** 04/21/05.sbm - Bug #306. Initial version.
** Code provided by Steve Kass - MS .programming newsgroup
BEGIN
DECLARE @place int
SET @place = 1
INSERT INTO @T (seq) VALUES (0)
WHILE @place <= @N/2 BEGIN
INSERT INTO @T (seq)
SELECT @place + Seq FROM @T
SET @place = @place + @place
END
INSERT INTO @T (seq)
SELECT @place + Seq FROM @T
WHERE Seq <= @N - @place
RETURN
END
go
For your particular case, the choice of a default constraint is likely due to the implementation of the logic in the function. Perhaps there are multiple insert statements and it was simpler/easier/more robust to use a default constraint rather than
repeatedly hard-code the value in each statement. By choosing a default constraint, the developer need only alter the constraint (once) if the value needs to be changed rather than finding and changing each statement that inserts or updates the table.
As you've have already discerned, you can simply ignore any constraints that are defined on the tables returned by a TVF. -
How to find out the Area Menu for a Report/ Table/Function Module
Hi,
Is there any procedure to find out the <b>"AREA MEANU"</b> for a Report/Table/Function Module...
Or is there any Transaction code / Report is available to find out all the report for a particular "AREA MENU".
Thank you for your quick response...
Regards,
Thiru
<b></b>Hi,
Check these below threads:
user log in & log out time SAO
How to find user log-out time ?
Regards,
Nitin -
Need some help with the Table Function Operator
I'm on OWB 10gR2 for Sun/Solaris 10 going against some 10gR2 DB's...
I've been searching up and down trying to figure out how to make OWB use a Table Function (TF) which will JOIN with another table; allowing a column of the joined table to be a parameter in to the TF. I can't seem to get it to work. I'm able to get this to work in regular SQL, though. Here's the setup:
-- Source Table:
DROP TABLE "ZZZ_ROOM_MASTER_EX";
CREATE TABLE "ZZZ_ROOM_MASTER_EX"
( "ID" NUMBER(8,0),
"ROOM_NUMBER" VARCHAR2(200),
"FEATURES" VARCHAR2(4000)
-- Example Data:
Insert into ZZZ_ROOM_MASTER_EX (ID,ROOM_NUMBER,FEATURES) values (1,'Room 1',null);
Insert into ZZZ_ROOM_MASTER_EX (ID,ROOM_NUMBER,FEATURES) values (2,'Room 2',null);
Insert into ZZZ_ROOM_MASTER_EX (ID,ROOM_NUMBER,FEATURES) values (3,'Room 3','1,1;2,3;');
Insert into ZZZ_ROOM_MASTER_EX (ID,ROOM_NUMBER,FEATURES) values (4,'Room 4','5,2;5,4;');
Insert into ZZZ_ROOM_MASTER_EX (ID,ROOM_NUMBER,FEATURES) values (5,'Room 5',' ');
-- Destination Table:
DROP TABLE "ZZZ_ROOM_FEATURES_EX";
CREATE TABLE "ZZZ_ROOM_FEATURES_EX"
( "ROOM_NUMBER" VARCHAR2(200),
"FEATUREID" NUMBER(8,0),
"QUANTITY" NUMBER(8,0)
-- Types for output table:
CREATE OR REPLACE TYPE FK_Row_EX AS OBJECT
ID NUMBER(8,0),
QUANTITY NUMBER(8,0)
CREATE OR REPLACE TYPE FK_Table_EX AS TABLE OF FK_Row_EX;
-- Package Dec:
CREATE OR REPLACE
PACKAGE ZZZ_SANDBOX_EX IS
FUNCTION UNFK(inputString VARCHAR2) RETURN FK_Table_EX;
END ZZZ_SANDBOX_EX;
-- Package Body:
CREATE OR REPLACE
PACKAGE BODY ZZZ_SANDBOX_EX IS
FUNCTION UNFK(inputString VARCHAR2) RETURN FK_Table_EX
AS
RETURN_VALUE FK_Table_EX := FK_Table_EX();
i NUMBER(8,0) := 0;
BEGIN
-- TODO: Put some real code in here that will actually read the
-- input string, parse it out, and put data in to RETURN_VALUE
WHILE(i < 3) LOOP
RETURN_VALUE.EXTEND;
RETURN_VALUE(RETURN_VALUE.LAST) := FK_Row_EX(4, 5);
i := i + 1;
END LOOP;
RETURN RETURN_VALUE;
END UNFK;
END ZZZ_SANDBOX_EX;
I've got a source system built by lazy DBA's and app developers who decided to store foreign keys for many-to-many relationships as delimited structures in driving tables. I need to build a generic table function to parse this data and return it as an actual table. In my example code, I don't actually have the parsing part written yet (I need to see how many different formats the source system uses first) so I just threw in some stub code to generate a few rows of 4's and 5's to return.
I can get the data from my source table to my destination table using the following SQL statement:
-- from source table joined with table function
INSERT INTO ZZZ_ROOM_FEATURES_EX(
ROOM_NUMBER,
FEATUREID,
QUANTITY)
SELECT
ZZZ_ROOM_MASTER_EX.ROOM_NUMBER,
UNFK.ID,
UNFK.QUANTITY
FROM
ZZZ_ROOM_MASTER_EX,
TABLE(ZZZ_SANDBOX_EX.UNFK(ZZZ_ROOM_MASTER_EX.FEATURES)) UNFK
Now, the big question is--how do I do this from OWB? I've tried several different variations of my function and settings in OWB to see if I can build a single SELECT statement which joins a regular table with a table function--but none of them seem to work, I end up getting SQL generated that won't compile because it doesn't see the source table right:
INSERT
/*+ APPEND PARALLEL("ZZZ_ROOM_FEATURES_EX") */
INTO
"ZZZ_ROOM_FEATURES_EX"
("ROOM_NUMBER",
"FEATUREID",
"QUANTITY")
(SELECT
"ZZZ_ROOM_MASTER_EX"."ROOM_NUMBER" "ROOM_NUMBER",
"INGRP2"."ID" "ID_1",
"INGRP2"."QUANTITY" "QUANTITY"
FROM
(SELECT
"UNFK"."ID" "ID",
"UNFK"."QUANTITY" "QUANTITY"
FROM
TABLE ( "ZZZ_SANDBOX_EX"."UNFK2" ("ZZZ_ROOM_MASTER_EX"."FEATURES")) "UNFK") "INGRP2",
"ZZZ_ROOM_MASTER_EX" "ZZZ_ROOM_MASTER_EX"
As you can see, it's trying to create a sub-query in the FROM clause--causing it to just ask for "ZZZ_ROOM_MASTER_EX"."FEATURES" as an input--which isn't available because it's outside of the sub-query!
Is this some kind of bug with the code generator or am I doing something seriously wrong here? Any help will be greatly appreciated!Hello Everybody!
Thank you for all your response!
I had changes this work area into Internal table and changed the select query. PLease let me know if this causes any performance issues?
I had created a Z table with the following fields :
ZADS :
MANDT
VKORG
ABGRU.
I had written a select query as below :
I had removed the select single and insted of using the Structure it_rej, I had changed it into Internal table
select vkorg abgru from ZADS into it_rej.
Earlier :
IT_REJ is a Work area:
DATA : BEGIN OF IT_REJ,
VKORG TYPE VBAK-VKORG,
ABGRU TYPE VBAP-ABGRU,
END OF IT_REJ.
Now :
DATA : BEGIN OF IT_REJ occurs 0,
VKORG TYPE VBAK-VKORG,
ABGRU TYPE VBAP-ABGRU,
END OF IT_REJ.
I guess this will fix the issue correct?
PLease suggest!
Regards,
Developer.
Maybe you are looking for
-
How do I download my purchased ringtones to my new iPhone?
How do I download my purchased ringtones to my new iPhone? I'm trying n it wnt let me download them!
-
Can CMT Session Bean call BMP Entity Bean in WebLogic 6.0?
Hi Does anybody successfully use CMT Session Bean calling BMP +CMT Entity bean in WebLogic6.0? I have the following problem. Any idea will be appreciated. --Winston Let's say we have a Sessi
-
hi out there I have defined a vPC between 2 sets of nexus boxes: nx51 ----vpc11--><--------vpc21--------nx53 II II vpc10 peerlink vpc20 peerlink II II nx52-----vpc11--><---------vpc21------nx54 vpc10 & vpc20 is running lacp but vpc11 & 21 are not - I
-
How do you use the iSight to just take a still photo, instead of video? I can't find this anywhere.
-
Maximum Volume Control - Padlocked!!!
Hi ipod guys Can anyone tell me how to unlock the maximum volume control - seems that a combination has been set, but I don't know what it is, so can't adjust the volume control. Is there a way to re-set it to 0000? I've looked all through discussion