A question came in recently.

“Can we exchange a partition from one partitioned table to another without using non-partitioned table as an interim? “

The answer is no. As per the docs

image

However, if this is a common requirement and you would like the equivalent of:

alter table T1 exchange partition PX with table T2 partition PY

then all it takes is a little PL/SQL to build an API to allow this.


SQL> create sequence seq;

Sequence created.

SQL> create or replace
  2  procedure exchange_par(
  3              p_table1 varchar2,
  4              p_table2 varchar2,
  5              p_table1_par varchar2,
  6              p_table2_par varchar2) is
  7    l_tab_cnt int;
  8    l_hash_cnt int;
  9    l_interim varchar2(100);
 10  begin
 11    select count(distinct tot), count(*)
 12    into   l_hash_cnt, l_tab_cnt
 13    from
 14      ( select table_name, sum(ora_hash(column_name)) tot
 15        from   user_tab_cols
 16        where  table_name in (p_table1,p_table2)
 17        group by table_name
 18      );
 19
 20    if l_tab_cnt != 2 or l_hash_cnt != 1 then
 21      raise_application_error(-20000,'Dead in the water');
 22    end if;
 23    l_interim := 'TMPTAB$'||seq.nextval;
 24
 25    begin
 26      execute immediate
 27        'drop table '||l_interim||' purge';
 28    exception
 29      when others then
 30        if sqlcode = -942 then null; else raise; end if;
 31    end;
 32
 33    execute immediate
 34      'create table '||l_interim||' for exchange with table '||p_table1;
 35
 36    execute immediate
 37      'alter table '||p_table1||' exchange partition '||p_table1_par||
 38      ' with table '||l_interim;
 39
 40    execute immediate
 41      'alter table '||p_table2||' exchange partition '||p_table2_par||
 42      ' with table '||l_interim;
 43
 44    execute immediate
 45      'drop table '||l_interim||' purge';
 46
 47  end;
 48  /

Procedure created.

The premise here is simple. We’ll do two exchange partition commands

  • The first one being from the source table to a temporary table
  • The second one being from the temporary table to the true target table.

Lines 11-18 are just a little safety net to protect this from ourselves – we make sure that the column names (including the hidden ones) are highly probable to be in alignment via some simple hashing. It is left as a reader exercise to extend this to data types and the like. (It is not critical because the exchange partition command will simply fail if the database decides it cannot be done).

Now we can create a couple of tables to see it in action



SQL> create table t1
  2  partition by list ( owner) automatic
  3  ( partition px values ('SYS') )
  4  as select * from dba_objects;

Table created.

SQL>
SQL> create table t2
  2  partition by list ( owner) automatic
  3  ( partition py values ('SYS') )
  4  as select * from dba_objects;

Table created.

SQL>
SQL> create table t3
  2  partition by list ( owner) automatic
  3  ( partition pz values ('SYSTEM') )
  4  as select * from dba_segments;

Table created.

Tables T1 and T2 should be ok to do a swap



SQL> exec exchange_par('T1','T2','PX','PY');

PL/SQL procedure successfully completed.

And tables T1 and T3 should not be ok due to the differing table structures.



SQL> exec exchange_par('T1','T3','PX','PZ');
BEGIN exchange_par('T1','T3','PX','PZ'); END;

*
ERROR at line 1:
ORA-20000: Dead in the water
ORA-06512: at "MCDONAC.EXCHANGE_PAR", line 20
ORA-06512: at line 1

The routine can be made as sophisticated as you like, eg, you could also take care of handling the indexes with appropriate use of UPDATE INDEXES in the DDL, or INCLUDING/EXCLUDING VALIDATION clauses depending on your needs. But the main point of this post is that the limitations as per the docs are trivially worked around with a little PL/SQL.

Got some thoughts? Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Trending