10g: parallel pipelined table func. using table(cast(SQL collect.))?

Hi,
i try to distribute SQL data objects - stored in a SQL data type TABLE OF <object-Type> - to multiple (parallel) instances of a table function,
by passing a CURSOR(...) to the table function, which selects from the SQL TABLE OF storage via "select * from TABLE(CAST(<storage> as <storage-type>)".
But oracle always only uses a single table function instance :-(
whatever hints i provide or setting i use for the parallel table function (parallel_enable ...)
Could it be, that this is due to the fact, that my data are not
globally available, but only in the main thread data?
Can someone confirm, that it's not possible to start multiple parallel table functions
for selecting on SQL data type TABLE OF <object>storages?
Here's an example sqlplus program to show the issue:
-------------------- snip ---------------------------------------------
set serveroutput on;
drop table test_table;
drop type ton_t;
drop type test_list;
drop type test_obj;
create table 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 TF(mycur test_cur)
return test_list pipelined
parallel_enable(partition mycur by hash(a));
end;
create or replace package body test_pkg
as
     function TF(mycur test_cur)
return test_list pipelined
parallel_enable(partition mycur by hash(a))
is
          sid number;
          counter number(19,0) := 0;
          myrec test_rec;
          mytab test_tab;
          mytab2 test_list := test_list();
     begin
          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));
               counter := counter + 1;
          end loop;
          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();
begin
     for i in 1..10000 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));
     dbms_output.put_line(chr(10) || 'copy ''mylist'' to ''mylist2'' by streaming via table function...');
     select test_obj(a, b, c) bulk collect into myList2
     from table(test_pkg.TF(CURSOR(select /*+ parallel(tab,10) */ * from table(cast (myList as test_list)) tab)));
     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('worker thread''s sid list:');
     for i in sids.first..sids.last loop
          dbms_output.put_line('sid #' || sids(i));
     end loop;
     dbms_output.put_line(chr(10) || 'copy physical ''test_table'' to ''mylist2'' by streaming via table function:');
     select test_obj(a, b, c) bulk collect into myList2
     from table(test_pkg.TF(CURSOR(select /*+ parallel(tab,10) */ * from test_table tab)));
     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('worker thread''s sid list:');
     for i in sids.first..sids.last loop
          dbms_output.put_line('sid #' || sids(i));
     end loop;
end;
-------------------- snap ---------------------------------------------
Here's the output:
-------------------- snip ---------------------------------------------
copy 'mylist' to 'mylist2' by streaming via table function...
test_pkg.TF( sid => '98' ): enter
test_pkg.TF( sid => '98' ): exit, piped #10000 records
... saved #10000 records
worker thread's sid list:
sid #98 -- ONLY A SINGLE SID HERE!
copy physical 'test_table' to 'mylist2' by streaming via table function:
... saved #10000 records
worker thread's sid list:
sid #128 -- A LIST OF SIDS HERE!
sid #141
sid #85
sid #125
sid #254
sid #101
sid #124
sid #109
sid #142
sid #92
PL/SQL procedure successfully completed.
-------------------- snap ---------------------------------------------
I posted it to newsgroup comp.databases.oracle.server.
(summary: "10g: parallel pipelined table functions with cursor selecting from table(cast(SQL collection)) doesn't work ")
But i didn't get a response.
There i also wrote some background information about my application:
-------------------- snip ---------------------------------------------
My application has a #2 steps/stages data selection.
A 1st select for minimal context base data
- mainly to evaluate for due driving data records.
And a 2nd select for all the "real" data to process a context
(joining much more other tables here, which i don't want to do for non-due records).
So it's doing stage #1 select first, then stage #2 select - based on stage #1 results - next.
The first implementation of the application did the stage #1 select in the main session of the pl/sql code.
And for the stage #2 select there was done a dispatch to multiple parallel table functions (in multiple worker sessions) for the "real work".
That worked.
However there was a flaw:
Between records from stage #1 selection and records from stage #2 selection there is a 1:n relation (via key / foreign key relation).
Means, for #1 resulting record from stage #1 selection, there are #x records from stage #2 selection.
That forced me to use "cluster curStage2 by (theKey)".
Because the worker sessions need to evaluate the all-over status for a context of #1 record from stage #1 and #x records from stage #2
(so it needs to have #x records of stage #2 together).
This then resulted in delay for starting up the worker sessions (i didn't find a way to get rid of this).
So i wanted to shift the invocation of the worker sessions to the stage #1 selection.
Then i don't need the "cluster curStage2 by (theKey)" anymore!
But: i also need to do an update of the primary driving data!
So the stage #1 select is a 'select ... for update ...'.
But you can't use such in CURSOR for table functions (which i can understand, why it's not possible).
So i have to do my stage #1 selection in two steps:
1. 'select for update' by main session and collect result in SQL collection.
2. pass collected data to parallel table functions
And for 2. i recognized, that it doesn't start up multiple parallel table function instances.
As a work-around
- if it's just not possible to start multiple parallel pipelined table functions for dispatching from 'select * from TABLE(CAST(... as ...))' -
i need to select again on the base tables - driven by the SQL collection data.
But before i do so, i wanted to verify, if it's really not possible.
Maybe i just miss a special oracle hint or whatever you can get "out of another box" :-)
-------------------- snap ---------------------------------------------
- many thanks!
rgds,
Frank

Hi,
i try to distribute SQL data objects - stored in a SQL data type TABLE OF <object-Type> - to multiple (parallel) instances of a table function,
by passing a CURSOR(...) to the table function, which selects from the SQL TABLE OF storage via "select * from TABLE(CAST(<storage> as <storage-type>)".
But oracle always only uses a single table function instance :-(
whatever hints i provide or setting i use for the parallel table function (parallel_enable ...)
Could it be, that this is due to the fact, that my data are not
globally available, but only in the main thread data?
Can someone confirm, that it's not possible to start multiple parallel table functions
for selecting on SQL data type TABLE OF <object>storages?
Here's an example sqlplus program to show the issue:
-------------------- snip ---------------------------------------------
set serveroutput on;
drop table test_table;
drop type ton_t;
drop type test_list;
drop type test_obj;
create table 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 TF(mycur test_cur)
return test_list pipelined
parallel_enable(partition mycur by hash(a));
end;
create or replace package body test_pkg
as
     function TF(mycur test_cur)
return test_list pipelined
parallel_enable(partition mycur by hash(a))
is
          sid number;
          counter number(19,0) := 0;
          myrec test_rec;
          mytab test_tab;
          mytab2 test_list := test_list();
     begin
          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));
               counter := counter + 1;
          end loop;
          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();
begin
     for i in 1..10000 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));
     dbms_output.put_line(chr(10) || 'copy ''mylist'' to ''mylist2'' by streaming via table function...');
     select test_obj(a, b, c) bulk collect into myList2
     from table(test_pkg.TF(CURSOR(select /*+ parallel(tab,10) */ * from table(cast (myList as test_list)) tab)));
     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('worker thread''s sid list:');
     for i in sids.first..sids.last loop
          dbms_output.put_line('sid #' || sids(i));
     end loop;
     dbms_output.put_line(chr(10) || 'copy physical ''test_table'' to ''mylist2'' by streaming via table function:');
     select test_obj(a, b, c) bulk collect into myList2
     from table(test_pkg.TF(CURSOR(select /*+ parallel(tab,10) */ * from test_table tab)));
     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('worker thread''s sid list:');
     for i in sids.first..sids.last loop
          dbms_output.put_line('sid #' || sids(i));
     end loop;
end;
-------------------- snap ---------------------------------------------
Here's the output:
-------------------- snip ---------------------------------------------
copy 'mylist' to 'mylist2' by streaming via table function...
test_pkg.TF( sid => '98' ): enter
test_pkg.TF( sid => '98' ): exit, piped #10000 records
... saved #10000 records
worker thread's sid list:
sid #98 -- ONLY A SINGLE SID HERE!
copy physical 'test_table' to 'mylist2' by streaming via table function:
... saved #10000 records
worker thread's sid list:
sid #128 -- A LIST OF SIDS HERE!
sid #141
sid #85
sid #125
sid #254
sid #101
sid #124
sid #109
sid #142
sid #92
PL/SQL procedure successfully completed.
-------------------- snap ---------------------------------------------
I posted it to newsgroup comp.databases.oracle.server.
(summary: "10g: parallel pipelined table functions with cursor selecting from table(cast(SQL collection)) doesn't work ")
But i didn't get a response.
There i also wrote some background information about my application:
-------------------- snip ---------------------------------------------
My application has a #2 steps/stages data selection.
A 1st select for minimal context base data
- mainly to evaluate for due driving data records.
And a 2nd select for all the "real" data to process a context
(joining much more other tables here, which i don't want to do for non-due records).
So it's doing stage #1 select first, then stage #2 select - based on stage #1 results - next.
The first implementation of the application did the stage #1 select in the main session of the pl/sql code.
And for the stage #2 select there was done a dispatch to multiple parallel table functions (in multiple worker sessions) for the "real work".
That worked.
However there was a flaw:
Between records from stage #1 selection and records from stage #2 selection there is a 1:n relation (via key / foreign key relation).
Means, for #1 resulting record from stage #1 selection, there are #x records from stage #2 selection.
That forced me to use "cluster curStage2 by (theKey)".
Because the worker sessions need to evaluate the all-over status for a context of #1 record from stage #1 and #x records from stage #2
(so it needs to have #x records of stage #2 together).
This then resulted in delay for starting up the worker sessions (i didn't find a way to get rid of this).
So i wanted to shift the invocation of the worker sessions to the stage #1 selection.
Then i don't need the "cluster curStage2 by (theKey)" anymore!
But: i also need to do an update of the primary driving data!
So the stage #1 select is a 'select ... for update ...'.
But you can't use such in CURSOR for table functions (which i can understand, why it's not possible).
So i have to do my stage #1 selection in two steps:
1. 'select for update' by main session and collect result in SQL collection.
2. pass collected data to parallel table functions
And for 2. i recognized, that it doesn't start up multiple parallel table function instances.
As a work-around
- if it's just not possible to start multiple parallel pipelined table functions for dispatching from 'select * from TABLE(CAST(... as ...))' -
i need to select again on the base tables - driven by the SQL collection data.
But before i do so, i wanted to verify, if it's really not possible.
Maybe i just miss a special oracle hint or whatever you can get "out of another box" :-)
-------------------- snap ---------------------------------------------
- many thanks!
rgds,
Frank

Similar Messages

  • How to hide system tables when using the Oracle SQL Developer?

    Hi,
    I would like to know how can I show only the tables that I created under the Tables tree? I didnt find a way to create a separate database using the Oracle Sql Developer. I see all the tables together, and would like to differentiate between different databases.
    Can anyone explain to me how to do these things?
    Thanks,

    Hi,
    I would like to know how can I show only the tables that I created under the Tables tree? Your posting is not clear,again tell something more on tables tree,what u want to achieve with it.
    How to hide system tables when using the Oracle SQL Developer? if u connected with sys, system or user with dba role then u have a privilege to see these tables,so revoke the privilege/role from ur user to view this tables if ur connected other then sys,system,
    I didnt find a way to create a separate database using the Oracle Sql Developer. DBCA is a tool for creating the new database.
    Kuljeet

  • Add a new record in database table without using table maintance generator

    Hi Expart ,
                  Plz. tell me how to add new record in database table without using table maintance ganerator ....give me one ex.
    Regards
    Bhabani

    Hi,
    The other way to safely handle the modification of tables is through is by programs that can be done with SE38 or SE80.
    To insert into database table we use INSERT statement :
    1. To insert a single line into a database table, use the following:
    INSERT INTO <target> VALUES <wa>.
    INSERT <target> FROM <wa>.
    2. To insert a several lines into a database table, use the following:
    INSERT <target> FROM TABLE <itaba>.
    Or even we can use MODIFY statementas this single statement is used to insert as well as update the records of database table.
    MODIFY <target> FROM <wa>.
    or MODIFY <target> FROM TABLE <itab>.
    thanx.
    Edited by: Dhanashri Pawar on Sep 10, 2008 12:25 PM
    Edited by: Dhanashri Pawar on Sep 10, 2008 12:30 PM

  • 10g: parallel pipelined table func - distributing DISTINCT data sets

    Hi,
    i want to distribute data records, selected from cursor, via parallel pipelined table function to multiple worker threads for processing and returning result records.
    The tables, where i am selecting data from, are partitioned and subpartitioned.
    All tables share the same partitioning/subpartitioning schema.
    Each table has a column 'Subpartition_Key', which is hashed to a physical subpartition.
    E.g. the Subpartition_Key ranges from 000...999, but we have only 10 physical subpartitions.
    The select of records is done partition-wise - one partition after another (in bulks).
    The parallel running worker threads select more data from other tables for their processing (2nd level select)
    Now my goal is to distribute initial records to the worker threads in a way, that they operate on distinct subpartitions - to decouple the access to resources (for the 2nd level select)
    But i cannot just use 'parallel_enable(partition curStage1 by hash(subpartition_key))' for the distribution.
    hash(subpartition_key) (hashing A) does not match with the hashing B used to assign the physical subpartition for the INSERT into the tables.
    Even when i remodel the hashing B, calculate some SubPartNo(subpartition_key) and use that for 'parallel_enable(partition curStage1 by hash(SubPartNo))' it doesn't work.
    Also 'parallel_enable(partition curStage1 by range(SubPartNo))' doesn't help. The load distribution is unbalanced - some worker threads get data of one subpartition, some of multiple subpartitions, some are idle.
    How can i distribute the records to the worker threads according a given subpartition-schema?
    +[amendment:+
    Actually the hashing for the parallel_enable is counterproductive here - it would be better to have some 'parallel_enable(partition curStage1 by SubPartNo)'.]
    - many thanks!
    best regards,
    Frank
    Edited by: user8704911 on Jan 12, 2012 2:51 AM

    Hello
    A couple of things to note. 1, when you use partition by hash(or range) on 10gr2 and above, there is an additional BUFFER SORT operation vs using partition by ANY. For small datasets this is not necessarily an issue, but the temp space used by this stage can be significant for larger data sets. So be sure to check temp space usage for this process or you could run into problems later.
    | Id  | Operation                             | Name     | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |    TQ  |IN-OUT| PQ Distrib |
    |   0 | SELECT STATEMENT                      |          |  8168 |  1722K|    24   (0)| 00:00:01 |       |       |        |      |            |
    |   1 |  PX COORDINATOR                       |          |       |       |            |          |       |       |        |      |            |
    |   2 |   PX SEND QC (RANDOM)                 | :TQ10001 |  8168 |  1722K|    24   (0)| 00:00:01 |       |       |  Q1,01 | P->S | QC (RAND)  |
    |   3 |****BUFFER SORT****                    |          |  8168 |  1722K|            |          |       |       |  Q1,01 | PCWP |            |
    |   4 |     VIEW                              |          |  8168 |  1722K|    24   (0)| 00:00:01 |       |       |  Q1,01 | PCWP |            |
    |   5 |      COLLECTION ITERATOR PICKLER FETCH| TF       |       |       |            |          |       |       |  Q1,01 | PCWP |            |
    |   6 |       PX RECEIVE                      |          |   100 |  4800 |     2   (0)| 00:00:01 |       |       |  Q1,01 | PCWP |            |
    |   7 |        PX SEND HASH                   | :TQ10000 |   100 |  4800 |     2   (0)| 00:00:01 |       |       |  Q1,00 | P->P | HASH       |
    |   8 |         PX BLOCK ITERATOR             |          |   100 |  4800 |     2   (0)| 00:00:01 |     1 |    10 |  Q1,00 | PCWC |            |
    |   9 |          TABLE ACCESS FULL            | TEST_TAB |   100 |  4800 |     2   (0)| 00:00:01 |     1 |    20 |  Q1,00 | PCWP |            |
    -----------------------------------------------------------------------------------------------------------------------------------------------It may be in this case that you can use clustering with partition by any to achieve your goal...
    create or replace package test_pkg as
         type Test_Tab_Rec_t is record (
              Tracking_ID                 number(19),
              Partition_Key               date,
              Subpartition_Key            number(3),
              sid                    number
         type Test_Tab_Rec_Tab_t is table of Test_Tab_Rec_t;
         type Test_Tab_Rec_Hash_t is table of Test_Tab_Rec_t index by binary_integer;
         type Test_Tab_Rec_HashHash_t is table of Test_Tab_Rec_Hash_t index by binary_integer;
         type Cur_t is ref cursor return Test_Tab_Rec_t;
         procedure populate;
         procedure report;
         function tf(cur in Cur_t)
         return test_list pipelined
         parallel_enable(partition cur by hash(subpartition_key));
         function tf_any(cur in Cur_t)
         return test_list PIPELINED
        CLUSTER cur BY (Subpartition_Key)
         parallel_enable(partition cur by ANY);   
    end;
    create or replace package body test_pkg as
         procedure populate
         is
              Tracking_ID number(19) := 1;
              Partition_Key date := current_timestamp;
              Subpartition_Key number(3) := 1;
         begin
              dbms_output.put_line(chr(10) || 'populate data into Test_Tab...');
              for Subpartition_Key in 0..99
              loop
                   for ctr in 1..1
                   loop
                        insert into test_tab (tracking_id, partition_key, subpartition_key)
                        values (Tracking_ID, Partition_Key, Subpartition_Key);
                        Tracking_ID := Tracking_ID + 1;
                   end loop;
              end loop;
              dbms_output.put_line('...done (populate data into Test_Tab)');
         end;
         procedure report
         is
              recs Test_Tab_Rec_Tab_t;
         begin
              dbms_output.put_line(chr(10) || 'list data per partition/subpartition...');
              for item in (select partition_name, subpartition_name from user_tab_subpartitions where table_name='TEST_TAB' order by partition_name, subpartition_name)
              loop
                   dbms_output.put_line('partition/subpartition = '  || item.partition_name || '/' || item.subpartition_name || ':');
                   execute immediate 'select * from test_tab SUBPARTITION(' || item.subpartition_name || ')' bulk collect into recs;
                   if recs.count > 0
                   then
                        for i in recs.first..recs.last
                        loop
                             dbms_output.put_line('...' || recs(i).Tracking_ID || ', ' || recs(i).Partition_Key  || ', ' || recs(i).Subpartition_Key);
                        end loop;
                   end if;
              end loop;
              dbms_output.put_line('... done (list data per partition/subpartition)');
         end;
         function tf(cur in Cur_t)
         return test_list pipelined
         parallel_enable(partition cur by hash(subpartition_key))
         is
              sid number;
              input Test_Tab_Rec_t;
              output test_object;
         begin
              select userenv('SID') into sid from dual;
              loop
                   fetch cur into input;
                   exit when cur%notfound;
                   output := test_object(input.tracking_id, input.partition_key, input.subpartition_key,sid);
                   pipe row(output);
              end loop;
         end;
         function tf_any(cur in Cur_t)
         return test_list PIPELINED
        CLUSTER cur BY (Subpartition_Key)
         parallel_enable(partition cur by ANY)
         is
              sid number;
              input Test_Tab_Rec_t;
              output test_object;
         begin
              select userenv('SID') into sid from dual;
              loop
                   fetch cur into input;
                   exit when cur%notfound;
                   output := test_object(input.tracking_id, input.partition_key, input.subpartition_key,sid);
                   pipe row(output);
              end loop;
         end;
    end;
    XXXX> with parts as (
      2  select --+ materialize
      3      data_object_id,
      4      subobject_name
      5  FROM
      6      user_objects
      7  WHERE
      8      object_name = 'TEST_TAB'
      9  and
    10      object_type = 'TABLE SUBPARTITION'
    11  )
    12  SELECT
    13        COUNT(*),
    14        parts.subobject_name,
    15        target.sid
    16  FROM
    17        parts,
    18        test_tab tt,
    19        test_tab_part_hash target
    20  WHERE
    21        tt.tracking_id = target.tracking_id
    22  and
    23        parts.data_object_id = DBMS_MView.PMarker(tt.rowid)
    24  GROUP BY
    25        parts.subobject_name,
    26        target.sid
    27  ORDER BY
    28        target.sid,
    29        parts.subobject_name
    30  /
    XXXX> INSERT INTO test_tab_part_hash select * from table(test_pkg.tf(CURSOR(select * from test_tab)))
      2  /
    100 rows created.
    Elapsed: 00:00:00.14
    XXXX>
    XXXX> INSERT INTO test_tab_part_any_cluster select * from table(test_pkg.tf_any(CURSOR(select * from test_tab)))
      2  /
    100 rows created.
    --using partition by hash
    XXXX> with parts as (
      2  select --+ materialize
      3      data_object_id,
      4      subobject_name
      5  FROM
      6      user_objects
      7  WHERE
      8      object_name = 'TEST_TAB'
      9  and
    10      object_type = 'TABLE SUBPARTITION'
    11  )
    12  SELECT
    13        COUNT(*),
    14        parts.subobject_name,
    15        target.sid
    16  FROM
    17        parts,
    18        test_tab tt,
    19        test_tab_part_hash target
    20  WHERE
    21        tt.tracking_id = target.tracking_id
    22  and
    23        parts.data_object_id = DBMS_MView.PMarker(tt.rowid)
    24  GROUP BY
    25        parts.subobject_name,
    26        target.sid
    27  /
      COUNT(*) SUBOBJECT_NAME                        SID
             3 SYS_SUBP31                           1272
             1 SYS_SUBP32                           1272
             1 SYS_SUBP33                           1272
             3 SYS_SUBP34                           1272
             1 SYS_SUBP36                           1272
             1 SYS_SUBP37                           1272
             3 SYS_SUBP38                           1272
             1 SYS_SUBP39                           1272
             1 SYS_SUBP32                           1280
             2 SYS_SUBP33                           1280
             2 SYS_SUBP34                           1280
             1 SYS_SUBP35                           1280
             2 SYS_SUBP36                           1280
             1 SYS_SUBP37                           1280
             2 SYS_SUBP38                           1280
             1 SYS_SUBP40                           1280
             2 SYS_SUBP33                           1283
             2 SYS_SUBP34                           1283
             2 SYS_SUBP35                           1283
             2 SYS_SUBP36                           1283
             1 SYS_SUBP37                           1283
             1 SYS_SUBP38                           1283
             2 SYS_SUBP39                           1283
             1 SYS_SUBP40                           1283
             1 SYS_SUBP32                           1298
             1 SYS_SUBP34                           1298
             1 SYS_SUBP36                           1298
             2 SYS_SUBP37                           1298
             4 SYS_SUBP38                           1298
             2 SYS_SUBP40                           1298
             1 SYS_SUBP31                           1313
             1 SYS_SUBP33                           1313
             1 SYS_SUBP39                           1313
             1 SYS_SUBP40                           1313
             1 SYS_SUBP32                           1314
             1 SYS_SUBP35                           1314
             1 SYS_SUBP38                           1314
             1 SYS_SUBP40                           1314
             2 SYS_SUBP33                           1381
             1 SYS_SUBP34                           1381
             1 SYS_SUBP35                           1381
             3 SYS_SUBP36                           1381
             3 SYS_SUBP37                           1381
             1 SYS_SUBP38                           1381
             2 SYS_SUBP36                           1531
             1 SYS_SUBP37                           1531
             2 SYS_SUBP38                           1531
             1 SYS_SUBP39                           1531
             1 SYS_SUBP40                           1531
             2 SYS_SUBP33                           1566
             1 SYS_SUBP34                           1566
             1 SYS_SUBP35                           1566
             1 SYS_SUBP37                           1566
             1 SYS_SUBP38                           1566
             2 SYS_SUBP39                           1566
             3 SYS_SUBP40                           1566
             1 SYS_SUBP32                           1567
             3 SYS_SUBP33                           1567
             3 SYS_SUBP35                           1567
             3 SYS_SUBP36                           1567
             1 SYS_SUBP37                           1567
             2 SYS_SUBP38                           1567
    62 rows selected.
    --using partition by any cluster by subpartition_key
    Elapsed: 00:00:00.26
    XXXX> with parts as (
      2  select --+ materialize
      3      data_object_id,
      4      subobject_name
      5  FROM
      6      user_objects
      7  WHERE
      8      object_name = 'TEST_TAB'
      9  and
    10      object_type = 'TABLE SUBPARTITION'
    11  )
    12  SELECT
    13        COUNT(*),
    14        parts.subobject_name,
    15        target.sid
    16  FROM
    17        parts,
    18        test_tab tt,
    19        test_tab_part_any_cluster target
    20  WHERE
    21        tt.tracking_id = target.tracking_id
    22  and
    23        parts.data_object_id = DBMS_MView.PMarker(tt.rowid)
    24  GROUP BY
    25        parts.subobject_name,
    26        target.sid
    27  ORDER BY
    28        target.sid,
    29        parts.subobject_name
    30  /
      COUNT(*) SUBOBJECT_NAME                        SID
            11 SYS_SUBP37                           1253
            10 SYS_SUBP34                           1268
             4 SYS_SUBP31                           1289
            10 SYS_SUBP40                           1314
             7 SYS_SUBP39                           1367
             9 SYS_SUBP35                           1377
            14 SYS_SUBP36                           1531
             5 SYS_SUBP32                           1572
            13 SYS_SUBP33                           1577
            17 SYS_SUBP38                           1609
    10 rows selected.Bear in mind though that this does require a sort of the incomming dataset but does not require buffering of the output...
    PLAN_TABLE_OUTPUT
    Plan hash value: 2570087774
    | Id  | Operation                            | Name     | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |    TQ  |IN-OUT| PQ Distrib |
    |   0 | SELECT STATEMENT                     |          |  8168 |  1722K|    24   (0)| 00:00:01 |       |       |        |      |            |
    |   1 |  PX COORDINATOR                      |          |       |       |            |          |       |       |        |      |            |
    |   2 |   PX SEND QC (RANDOM)                | :TQ10000 |  8168 |  1722K|    24   (0)| 00:00:01 |       |       |  Q1,00 | P->S | QC (RAND)  |
    |   3 |    VIEW                              |          |  8168 |  1722K|    24   (0)| 00:00:01 |       |       |  Q1,00 | PCWP |            |
    |   4 |     COLLECTION ITERATOR PICKLER FETCH| TF_ANY   |       |       |            |          |       |       |  Q1,00 | PCWP |            |
    |   5 |      SORT ORDER BY                   |          |       |       |            |          |       |       |  Q1,00 | PCWP |            |
    |   6 |       PX BLOCK ITERATOR              |          |   100 |  4800 |     2   (0)| 00:00:01 |     1 |    10 |  Q1,00 | PCWC |            |
    |   7 |        TABLE ACCESS FULL             | TEST_TAB |   100 |  4800 |     2   (0)| 00:00:01 |     1 |    20 |  Q1,00 | PCWP |            |
    ----------------------------------------------------------------------------------------------------------------------------------------------HTH
    David

  • How to implement line selectability for a table control using table Wizard?

    Hello SDN Community,
    I have created a table control using the Table Wizard.  I found my exact question in this forum, but unfortunately it had not been andsered.  While I cannot paste a screen-print into this plane-text area, here are the steps I followed...
    1) SE51
    2) Create new screen 0100
    3) Click Layout button
    4) Clidk Table Control (with Wizard) and draw box on canvas.
    5) Step is "Start" - click Continue
    6) Step is "Name of Table Control" - provided name
    7) Step is "Table Name" - provided name of dictionary table (AUFK)
    8) Step is "Definition of Columns" - selected order numver and order text
    9) Step is "Table Control Attributes" - Line Selectability is in display mode - cannot set it.
    I would like to have a selectability column for my table.  Would appreciate any insight into how to do this.
    Thank you,
    Dean Atteberry.

    This is a puzzling...
    For the table control wizard, in the Table Control Attributes step, I was able to get line selectability to open up by declaring a char01 data element at the beginning of my type.
    The puzzling is in regards to the "Selection col. fld" entry field.
    If I leave it blank and try to go to the next step, I get message "Enter the name of the selection column if you are using a program table"
    So it looked like it wanted to know the name of my selection column.  So I type in "CHAR1".  and got the message "The field "CHAR1" for the selection column is already contained in the table."
    Hmmmmm.... don't understand............
    Dean Atteberry.

  • How to Delete rows in the database table by using Table Control

    Hi Experts,
    I wrote one program.
    In that program i used table control.
    I displayed data from database table in the table control, but i want to delete selected rows.
    Can anybody please tell me this by writing sample code
    thank you
    Basu

    Hi ,
    Pls try this coding below or check the prg demo  - RSDEMO02 in se38
    WHEN 'DELL'.
    * remove marked lines
          LOOP AT IT_SPFLI WHERE MARKED = 'X'.
            DELETE IT_SPFLI.
          ENDLOOP.
          IF SY-SUBRC <> 0.
            GET CURSOR FIELD FLD LINE LINNO OFFSET OFF.
            SET CURSOR FIELD FLD LINE LINNO OFFSET OFF.
            IF FLD CP 'IT_SPFLI*' AND SY-SUBRC = 0.
              LINNO = LINNO + TC_SPFLI-TOP_LINE - 1.
              DELETE IT_SPFLI INDEX LINNO.
              TC_SPFLI-LINES = TC_SPFLI-LINES - 1.
            ENDIF.
          ENDIF.
    or another eg :
    MODULE USER_COMMAND_0100 INPUT.
        SAVE_CODE = OK_CODE.
        CLEAR OK_CODE.
        CASE SAVE_CODE.
    WHEN 'DELE'.
                CALL FUNCTION 'COPO_POPUP_TO_GOON'
                    EXPORTING
                         TEXTLINE1 = 'Selected rows will be deleted!'
                         TEXTLINE2 = 'Are you sure?'
                         TITEL     = 'Delete rows'
                    IMPORTING
                         answer    = confirmation.
                IF CONFIRMATION = 'G'.
                    REFRESH ITAB_PHONELIST.
                    CLEAR ITAB_PHONELIST.
                ENDIF.
    MODULE EXTRACT_USERDATA INPUT.
        CASE SAVE_CODE.
            WHEN 'DELE'.
                IF SELECTION IS INITIAL AND
                   confirmation = 'G'.
                     CLEAR ITAB_PHONELIST.
        ITAB_PHONELIST-NAME = RECORD-NAME.
        ITAB_PHONELIST-PHONE = RECORD-PHONE.
        ITAB_PHONELIST-EMAIL = RECORD-EMAIL.
        APPEND ITAB_PHONELIST.
    <b>Reward pts if found usefull :)</b>
    regards
    Sathish

  • Difference between Oracle 10g and Oracle 11g when using Distinct in SQL

    Hi All,
    When I use Distinct in Oracle 10g, the result would be sorted in ascending order automatically, while there is no sorting in the result set in Oracle 11g.
    I was using plsql developer to run my sql.
    May I know if anyone have the same experience before?
    Is there any kind of setting in 11g that I can make the result in order? Thanks!
    Edited by: user5810051 on 2011/4/6 下午 8:47

    As acadet says, if you want your result ordered you must specify an ORDER BY clause in your query. Just because previous versions of oracle included some ordering as part of the processing of a query, that was not a guaranteed ordering, but just a side-effect. Now that Oracle have improved the internal workings, they've removed the side-effect, and that's why you're not getting the ordering you want, because you were relying on that side-effect rather than explicitly stating the order you wanted.

  • HR-ABAP using Table Control Wizard

    My requirements is to customize an infotype which is customer specific.
    After creating the infotype in PM01, I also create the screen(2000) for the
    infotype. The issue is in the table control. I create a table control
    using  table control wizard, getting the information that i need to output in the
    screen, using another infotype which is PA0007 planned working time.
    The expected result is that the data will diplay on the screen when i execute PA30.
    Do you have any idea or any recommendation to resolve the issue? thanks.
    And here are my codes.
    in PBO
      LOOP AT   g_table5_itab
           INTO g_table5_wa
           WITH CONTROL table5
           CURSOR table5-current_line.
        MODULE table5_move.
        MODULE table5_get_lines.
      ENDLOOP.
    Inside the  module pool.
    MODULE TABLE5_INIT OUTPUT.
      IF G_TABLE5_COPIED IS INITIAL.
    *&SPWIZARD: COPY DDIC-TABLE 'PA0007'
    *&SPWIZARD: INTO INTERNAL TABLE 'g_TABLE5_itab'
        SELECT * FROM PA0007
           INTO CORRESPONDING FIELDS
           OF TABLE G_TABLE5_ITAB
    *Start of Insert
           WHERE pernr = pskey-pernr.
    *End of Insert      .
         G_TABLE5_COPIED = 'X'.
         REFRESH CONTROL 'TABLE5' FROM SCREEN '2000'.
      ENDIF.
    ENDMODULE.
    MODULE TABLE5_MOVE OUTPUT.
    *Start of Delete
      MOVE-CORRESPONDING G_TABLE5_WA TO PA0007.
       MOVE-CORRESPONDING G_TABLE5_WA TO PA9201.
    *End of Delete
    *Start of Change
       MOVE G_TABLE5_WA-begda TO PA9201-zzpensda.
       MOVE G_TABLE5_WA-endda TO PA9201-zzpendda.
       MOVE G_TABLE5_WA-empct TO PA9201-zzempct.
    *End of Change
    ENDMODULE.
    MODULE TABLE5_GET_LINES OUTPUT.
      G_TABLE5_LINES = SY-LOOPC.
    ENDMODULE.

    Hi,
    Create a table control in layout and place your fields in table control.
    Press F6 and give the table name and click on get from dictionary and select the 5 fields which you required and palce those fields in table control.
    Double click on table control and give table control name .
    In Top include create a stmt as
    CONTROLS : TABlecontrolname TYPE TABLEVIEW USING SCREEN '1000'.
    In PBO under a module write your logic that means select query and place it in an internal table. Place that select query under IF condition.
    Module Read.
    If SY-UCOMM = 'ENTER'.
    Process query.
    endif.
    endmodule.
      LOOP AT ITAB INTO WA WITH CONTROL TAB.
        MODULE DISP.
        ENDLOOP.
    In PAI.
       LOOP AT ITAB.
         ENDLOOP.
    Here ITAB is internal table name.TAB is table control name.In display module write the code
    MODULE DISP OUTPUT.
    MOVE-CORRESPONDING WA TO database tablename.
    ENDMODULE.
    And in 1000 screen create SET PF status in the function keys assign a keyword to Enter Icon as 'ENTER'.
    Hope this is helpful.
    Regards,
    G.Aditya

  • Using 3 tables in Merge function T-SQL

    Hi there,
    I have a source table A and one View ,Target table B
    I was trying to write Merge function for incremental load I mean it is type1 load
    Table A should look at View   if it doesn't find the record then load into table B (Target)
    the columns are ID and Type
    if ID is same and type name is different then should update type in the Table B (Target)
    I usually write merge function like below 
    Merge table x
    using table y
    on x.id=y.id
    when matched  then
    update set x.description=y.description
    when not matched then
    insert (id,description)
    values(id,description)
    but I don't understand how to write in my scenario. can anyone guide me please.

    Please try this.
    Declare @MergeData Table
    Col1 Int,
    Col2 Varchar(10),
    ActionDone Varchar(10)
    Select * Into #Temp_SourceA From SourceA
    Insert @MergeData
    Select Col1,Col2,ActionDone
    From
    Merge #Temp_SourceA As Trgt
    Using View_Source As Src
    On Trgt.Col1 = Src.Col1
    When Matched And
    Trgt.Col2 <> Src.Col2
    Then Update Set Trgt.Col2 = Src.Col2
    When Not Matched Then
    Insert (Col1,Col2)
    Values (Src.Col1,Src.Col2)
    Output $action ActionDone,Inserted.Col1,Inserted.Col2
    )Data
    Select * From @MergeData
    Insert Into TargetA
    Select Col1,Col2 From @MergeData Where ActionDone = 'INSERT'
    Update T1
    Set Col2 = T2.Col2
    From TargetA T1
    Inner Join @MergeData T2 On T1.Col1 = T2.Col1 And T2.ActionDone = 'Update'
    Drop Table #Temp_SourceA
    --Select * From View_Source
    --Select * From SourceA
    Please have look on the comment

  • Button "Position" can't work in sm30 when use Table maintenance generator

    Hello guys,
      i have created a table and use 'Table Maintenance Generator' to generate the code. When i run sm30 and click the button 'Position', it can not work.
       i enter '/h' to debug it and find the value'POSI' is not assigned to ok_code.
        Some tables created before are OK. What's the matter with it?
    Many Thanks

    hello daniel,
    there is very possibility that some inconsistency might be occured while generating table maintenance generator. So i would advice u to create ur table maintenance generator once more after deleting the current one.
    Reward properly.

  • Update info while using Table Maintenance

    Hi All,
    I have requirement to update user info and date & time in custom table whoever using Table Maintenance.
    ie.
    My requirement is if any user updating any table [SAP standard or Custom table] using table maintenance, then
    i need to update the user name, date and time into custom table.
    Can anbody suggest a solution for this.
    Thanks
    aRS

    Hi,
    Try this solution...This might work for custom tables..
    Create a new report program..
    Take the table name as a parameter..
    Then get all the contents from the table and store it in a internal table..
    Then call the transaction SM30 with the table name..
    Once they update the table and save..The control will come back to the report program...
    Then again get the values from the custom table..
    Compare the values..If there is any change...Then update your custom table with the user info..
    Thanks,
    Naren
    Message was edited by: Narendran Muthukumaran

  • 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,
    Frank

    Hello
    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

  • Parallel pipelined table function, autonomous_transaction to global tmp tab

    Hi,
    i try to speed up my parallel pipelined table function and switch from pl/sql collection to global temporary table inside.
    This requires to use PRAGMA AUTONOMOUS_TRANSACTION (and commit), because inserting into global temporary table (DML)
    within select - for invoking the table function - is not allowed without.
    As a consequence of commit it next requires to have on commit preserve rows for the global temporary table.
    Now:
    Inserts into the global temporary table are done - indicated by sql%rowcount.
    But a select afterwards doesn't show any record anymore.
    Here is a program to demonstrate it:
    set serveroutput on;
    drop type TestTableOfNumber_t;
    create or replace type TestTableOfNumber_t is table of number;
    drop type TestStatusList;
    drop type TestStatusObj;
    create or replace type TestStatusObj as object(
         sid number,
         ctr1 number,
         ctr2 number,
         ctr3 number
    create or replace type TestStatusList is table of TestStatusObj;
    drop table TestTmpTable;
    create global temporary table TestTmpTable (
         value     number
    ) on commit preserve rows;
    create or replace package test_pkg
    as
         type TestStatusRec is record (
              sid number,
              ctr1 number,
              ctr2 number,
              ctr3 number
         type TestStatusTab is table of TestStatusRec;
         function FillTmpTable(id in varchar2)
         return TestStatusRec;
         FUNCTION ptf (p_cursor  IN  sys_refcursor)
         RETURN TestStatusList PIPELINED
         PARALLEL_ENABLE(PARTITION p_cursor BY any);
    end;
    create or replace package body test_pkg
    as
         function FillTmpTable(id in varchar2)
         return TestStatusRec
         is
              PRAGMA AUTONOMOUS_TRANSACTION;
              result TestStatusRec;
              sid number;
              type ton is table of number;
              tids TestTableOfNumber_t := TestTableOfNumber_t();
              records number := 0;
         begin
              select userenv('SID') into sid from dual;
              result.sid := sid;
              delete from TestTmpTable;
              for i in 1..100 loop
                   tids.extend;
                   tids(tids.last) := i;
              end loop;
              forall i in 1..tids.count
                   insert into TestTmpTable (value) values (tids(i));
              -- get number of records inserted
              records := sql%rowcount;
              result.ctr1 := records;
              -- retrieve again before commit
              select count(*) into records from TestTmpTable;
              result.ctr2 := records;
              commit;
              -- retrieve again after commit
              select count(*) into records from TestTmpTable;
              result.ctr3 := records;
              return result;
         end;
           FUNCTION ptf (p_cursor  IN  sys_refcursor)
         RETURN TestStatusList PIPELINED
         PARALLEL_ENABLE(PARTITION p_cursor BY any)
         IS
              rec test_pkg.TestStatusRec;
              value number;
              sid number;
              ctr integer := 0;
         BEGIN
              select userenv('SID') into sid from dual;
              rec := FillTmpTable('IN PTF');
              LOOP
                   FETCH p_cursor into value;
                   EXIT WHEN p_cursor%NOTFOUND;
                   ctr := ctr + 1;     
              END LOOP;
              -- as a result i am only interested in the results of FillTmpTable():
              PIPE ROW (TestStatusObj(rec.sid, rec.ctr1, rec.ctr2, rec.ctr3));
                  RETURN;
         END;
    end;
    declare
         tons TestTableOfNumber_t;
         counts TestTableOfNumber_t;
         status test_pkg.TestStatusRec;
         statusList test_pkg.TestStatusTab;
    begin
         status := test_pkg.FillTmpTable('MAIN');
         dbms_output.put_line('main thread:'
              || ' sid #' || status.sid
              || ' / #' || status.ctr1 || ' inserted '
              || ' / #' || status.ctr2 || ' before commit'
              || ' / #' || status.ctr3 || ' after commit');     
         select value bulk collect into tons from TestTmpTable;
         select * bulk collect into statusList from TABLE(test_pkg.ptf(CURSOR(select /*+ parallel(tab,2) */ value from TestTmpTable tab)));
         for i in 1..StatusList.count loop
              dbms_output.put_line('worker thread #' || i  || ':'
              || ' sid #' || statusList(i).sid
              || ' / #' || statusList(i).ctr1 || ' inserted '
              || ' / #' || statusList(i).ctr2 || ' before commit'
              || ' / #' || statusList(i).ctr3 || ' after commit');
         end loop;
    end;
    /The output is:
    main thread: sid #881 / #100 inserted  / #100 before commit / #100 after commit
    worker thread #1: sid #421 / #100 inserted  / #0 before commit / #0 after commit
    worker thread #2: sid #321 / #100 inserted  / #0 before commit / #0 after commitThe 1st line is for the main thread invoking FillTmpTable().
    The next #2 lines are for the worker threads of the parallel pipelined table function for invoking the same FillTmpTable().
    For the main thread everything is as expected.
    But for the worker threads the logs for before commit and after commit both give #0 for the number of available records in the global temporary table.
    However all indicate #100 for the SQL insert
    regards,
    Frank
    Edited by: user8704911 on Jul 7, 2011 10:13 AM
    Edited by: user8704911 on Jul 7, 2011 10:20 AM
    Edited by: user8704911 on Jul 7, 2011 10:27 AM

    SQL> select * from v$version;
    BANNER
    Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production
    PL/SQL Release 11.1.0.7.0 - Production
    CORE    11.1.0.7.0      Production
    TNS for Linux: Version 11.1.0.7.0 - Production
    NLSRTL Version 11.1.0.7.0 - Production
    SQL> set serveroutput on;
    SQL> drop type TestTableOfNumber;
    drop type TestTableOfNumber
    ERROR at line 1:
    ORA-04043: object TESTTABLEOFNUMBER does not exist
    SQL> /
    drop type TestTableOfNumber
    ERROR at line 1:
    ORA-04043: object TESTTABLEOFNUMBER does not exist
    SQL> 
    SQL> create or replace type TestTableOfNumber_t is table of number;
      2  /
    Type created.
    SQL> 
    SQL> drop type TestStatusObj;
    drop type TestStatusObj
    ERROR at line 1:
    ORA-04043: object TESTSTATUSOBJ does not exist
    SQL> /
    drop type TestStatusObj
    ERROR at line 1:
    ORA-04043: object TESTSTATUSOBJ does not exist
    SQL> 
    SQL> create or replace type TestStatusObj as object(
      2   sid number,
      3   ctr1 number,
      4   ctr2 number,
      5   ctr3 number
      6  );
      7  /
    Type created.
    SQL> 
    SQL> drop type TestStatusList;
    drop type TestStatusList
    ERROR at line 1:
    ORA-04043: object TESTSTATUSLIST does not exist
    SQL> /
    drop type TestStatusList
    ERROR at line 1:
    ORA-04043: object TESTSTATUSLIST does not exist
    SQL> 
    SQL> create or replace type TestStatusList is table of TestStatusObj;
      2  /
    Type created.
    SQL> 
    SQL> drop table TestTmpTable;
    drop table TestTmpTable
    ERROR at line 1:
    ORA-00942: table or view does not exist
    SQL> /
    drop table TestTmpTable
    ERROR at line 1:
    ORA-00942: table or view does not exist
    SQL> 
    SQL> create global temporary table TestTmpTable (
      2   value number
      3  ) on commit preserve rows;
    Table created.
    SQL> /
    create global temporary table TestTmpTable (
    ERROR at line 1:
    ORA-00955: name is already used by an existing object
    SQL> 
    SQL> create or replace package test_pkg
      2  as
      3  
      4   type TestStatusRec is record (
      5    sid number,
      6    ctr1 number,
      7    ctr2 number,
      8    ctr3 number
      9   );
    10  
    11   type TestStatusTab is table of TestStatusRec;
    12  
    13   function FillTmpTable(id in varchar2)
    14   return TestStatusRec;
    15  
    16   FUNCTION ptf (p_cursor  IN  sys_refcursor)
    17   RETURN TestStatusList PIPELINED
    18   PARALLEL_ENABLE(PARTITION p_cursor BY any);
    19  
    20  end;
    21  /
    Package created.
    SQL> 
    SQL> create or replace package body test_pkg
      2  as
      3  
      4   function FillTmpTable(id in varchar2)
      5   return TestStatusRec
      6   is
      7    PRAGMA AUTONOMOUS_TRANSACTION;
      8  
      9    result TestStatusRec;
    10  
    11    sid number;
    12  
    13    type ton is table of number;
    14    tids TestTableOfNumber_t := TestTableOfNumber_t();
    15  
    16    records number := 0;
    17   begin
    18    select userenv('SID') into sid from dual;
    19    result.sid := sid;
    20  
    21    delete from TestTmpTable;
    22  
    23    for i in 1..100 loop
    24     tids.extend;
    25     tids(tids.last) := i;
    26    end loop;
    27  
    28    forall i in 1..tids.count
    29     insert into TestTmpTable (value) values (tids(i));
    30  
    31    -- get number of records inserted
    32    records := sql%rowcount;
    33    result.ctr1 := records;
    34  
    35    -- retrieve again before commit
    36    select count(*) into records from TestTmpTable;
    37    result.ctr2 := records;
    38  
    39    commit;
    40  
    41    -- retrieve again after commit
    42    select count(*) into records from TestTmpTable;
    43    result.ctr3 := records;
    44  
    45    return result;
    46   end;
    47  
    48     FUNCTION ptf (p_cursor  IN  sys_refcursor)
    49   RETURN TestStatusList PIPELINED
    50   PARALLEL_ENABLE(PARTITION p_cursor BY any)
    51   IS
    52    rec test_pkg.TestStatusRec;
    53    value number;
    54    sid number;
    55    ctr integer := 0;
    56   BEGIN
    57    select userenv('SID') into sid from dual;
    58    rec := FillTmpTable('IN PTF');
    59    LOOP
    60     FETCH p_cursor into value;
    61     EXIT WHEN p_cursor%NOTFOUND;
    62     ctr := ctr + 1;
    63    END LOOP;
    64  
    65    -- as a result i am only interested in the results of FillTmpTable():
    66    PIPE ROW (TestStatusObj(rec.sid, rec.ctr1, rec.ctr2, rec.ctr3));
    67  
    68        RETURN;
    69   END;
    70  end;
    71  /
    Package body created.
    SQL> 
    SQL> declare
      2   tons TestTableOfNumber_t;
      3   counts TestTableOfNumber_t;
      4   status test_pkg.TestStatusRec;
      5   statusList test_pkg.TestStatusTab;
      6  begin
      7   status := test_pkg.FillTmpTable('MAIN');
      8   dbms_output.put_line('main thread:'
      9    || ' sid #' || status.sid
    10    || ' / #' || status.ctr1 || ' inserted '
    11    || ' / #' || status.ctr2 || ' before commit'
    12    || ' / #' || status.ctr3 || ' after commit');
    13  
    14   select value bulk collect into tons from TestTmpTable;
    15  
    16   select * bulk collect into statusList from TABLE(test_pkg.ptf(CURSOR(select /*+ parallel(tab,2
    ) */ value from TestTmpTable tab)));
    17  
    18   for i in 1..StatusList.count loop
    19    dbms_output.put_line('worker thread #' || i  || ':'
    20    || ' sid #' || statusList(i).sid
    21    || ' / #' || statusList(i).ctr1 || ' inserted '
    22    || ' / #' || statusList(i).ctr2 || ' before commit'
    23    || ' / #' || statusList(i).ctr3 || ' after commit');
    24   end loop;
    25  
    26  end;
    27  /
    main thread: sid #1023 / #100 inserted  / #100 before commit / #100 after commit
    worker thread #1: sid #1045 / #100 inserted  / #100 before commit / #100 after
    commit
    worker thread #2: sid #1019 / #100 inserted  / #100 before commit / #100 after
    commit
    PL/SQL procedure successfully completed.
    SQL> I am getting a different result.
    Regards
    Raj

  • Derive found flag in SQL with where clause using TABLE(CAST function

    Dear All,
    Stored procedure listEmployees
    ==========================
    CREATE OR REPLACE TYPE STRING_ARRAY AS VARRAY(8000) OF VARCHAR2(15);
    empIdList STRING_ARRAY
    countriesList STRING_ARRAY
    SELECT EMP_ID, EMP_COUNTRY, EMP_NAME, FOUND_FLAG_
    FROM EMPLOYEE WHERE
    EMP_ID IN
    (SELECT * FROM TABLE(CAST(empIdList AS STRING_ARRAY))
    AND EMP_COUNTRY IN
    (SELECT * FROM TABLE(CAST(countriesList AS STRING_ARRAY))
    =================
    I have a stored procedure which lists the employees using above simple query.
    Here I am using table CAST function to find the list of employees in one go
    instead of looping through each and every employee
    Everything fine until requirements forced me to get the FOUND_FLAG as well.
    Now I wanted derive the FOUND_FLAG by using rownum, rowid, decode functions
    but I was not successful
    Can you please suggest if there is any intelligent way to say weather the
    row is found for given parameters in the where clause?
    If not I may have to loop through each set of empIdList, countriesList
    and find the values individually just to set a flag. In this approach I can’t use
    the TABLE CAST function which is efficient I suppose.
    Note that query STRING_ARRAY is an VARRAY. It is very big in size and this procedure
    suppose to handle large sets of data.
    Thanks In advance
    Regards
    Charan
    Edited by: kmcharan on 03-Dec-2009 09:55
    Edited by: kmcharan on 03-Dec-2009 09:55

    If your query returns results, you have found them... so your "FOUND" flag might be a constant,...

  • Help on CAST function, defining TYPE TABLE and using a REF cursor

    Hi,
    I have written a procedure (lookup) inside a package (lookup_pkg) as shown below.
    Procedure has an output variable of type PL/SQL TABLE which is defined in the package.
    I want to write a wrapper procedure lookupref to the procedure lookup to return a ref cursor.
    CREATE OR REPLACE PACKAGE lookup_pkg AS
    TYPE t_lookup_refcur IS REF CURSOR;
    CURSOR c_lookup IS
         Select columns1,2,3,....100
                   FROM A, B, C, D, E
                   WHERE ROWNUM < 1;
    TYPE t_lookup IS TABLE OF c_lookup%ROWTYPE;
    Procedure lookup(id Number, o_lookup OUT t_lookup);
    End lookup_pkg;
    CREATE OR REPLACE PACKAGE BODY lookup_pkg As
    Procedure lookup(id Number, o_lookup OUT t_lookup) IS
    BEGIN
    END lookup;
    Procedure lookupref(id Number, o_lookupref OUT t_lookup_refcur) IS
    o_lookup t_lookup;
    BEGIN
    lookup(id, o_lookup t_lookup);
    OPEN t_lookup_refcur FOR
    SELECT *
         FROM TABLE(CAST(o_lookup AS t_lookup));
    Exception
    End lookupref;
    END lookup_pkg;
    When I compile this procedure, I am getting invalid datatype Oracle error and
    cursor points the datatype t_lookup in the CAST function.
    1. Can anyone tell me what is wrong in this. Can I convert a PL/SQL collection (pl/sql table in this case) to PL/SQL datatype table or does it need to be a SQL datatype only (which is created as a type in database).
    Also, to resolve this error, I have created a SQL type and table type instead of PL/SQL table in the package as shown below.
    create or replace type t_lookuprec as object
                   (Select columns1,2,3,....100
                   FROM A, B, C, D, E
                   WHERE ROWNUM < 1);
    create or replace type t_lookup_tab AS table of t_lookuprec;
    CREATE OR REPLACE PACKAGE BODY lookup_pkg As
    Procedure lookup(id Number, o_lookup OUT t_lookup) IS
    BEGIN
    END lookup;
    Procedure lookupref(id Number, o_lookupref OUT t_lookup_refcur) IS
    o_lookup t_lookup;
    BEGIN
    lookup(id, o_lookup t_lookup);
    OPEN t_lookup_refcur FOR
    SELECT *
         FROM TABLE(CAST(o_lookup AS t_lookup_tab));
    Exception
    End lookupref;
    END lookup_pkg;
    When I compile this package, I am getting "PL/SQL: ORA-22800: invalid user-defined type" Oracle error and
    points the datatype t_lookup_tab in the CAST function.
    2. Can anyone tell me what is wrong. Can I create a type with a select statement and create a table type using type created earlier?
    I have checked the all_types view and found that
    value for Incomplete column for these two types are YES.
    3. What does that mean?
    Any suggestions and help is appreciated.
    Thanks
    Srinivas

    create or replace type t_lookuprec as object
    (Select columns1,2,3,....100
    FROM A, B, C, D, E
    WHERE ROWNUM < 1);You are correct that you need to use CREATE TYPE to use the type in SQL.
    However unless I am mistaken you appear to have invented your own syntax for CREATE TYPE, suggest you refer to Oracle documentation.

Maybe you are looking for

  • HT201343 Can I update my Mac to support airplay mirroring?

    Can I update my Mac to support airplay mirroring?

  • No excise duty in MIRO after stimulating

    Dear all I have created PO mantaing all excise duty,after GR done with capture and post the excise.when Iam doing w.r.t PO,taxes are calculating correctly but when u click simlate no excise part is coming only Vendor debit and GR/IR .- GL Account. re

  • Best dvd-r recording material

    I am having a problem searching for the best dvd-r material to use. I keep getting problems with canon dvd-r recording captures. Can someone guide me in the recommened brands of DVD-R material? I understand most people rely on Taiyo Yuden as the leas

  • Why is the colour in AI files different to the PDF version?

    Whenever I save my AI files to PDF format, the colour is very different. Can someone tell me why?  Both screenshots are CMYK below. AI on left and PDF on right.

  • Flash player update 11.5 or higher for windows 8

    Dear adobe team, I have a windows 8 laptop with adobe flash player version 11.3. One of my online games requires 11.5 or higher. I tried to update my version but the website tells me that available updates will be downloaded automatically when availa