Since Oracle 10g, Oracle provides a great tool to import and export data from databases: Data Pump. This tool offers several helpful options, particularly one that allows to import data in a different tablespace than the source database. This parameter is REMAP_TABLESPACE. However, how can you do the same when you cannot use Data Pump to perform Oracle import and export operations?

I was confronted with this issue recently, and I had to deal with different workarounds to accomplish my import successfully. The main case where you will not be able to use Datapump is when you want to export data from a pre-10g database. And believe me, there are still a lot more of these databases running over the world than we think! The Oracle Import/Export utility does not provide a built-in way to remap tablespace like Datapump. In this blog posting, I will address the different workarounds to import data in a different tablespace with the Oracle Import Export Tool.

I have used an Oracle 11g R2 database for all examples.

My source schema ‘MSC’ on the Oracle Database DB11G is using the default tablespace USERS. I want to import the data to a different schema ‘DBI’ using the USER_DATA tablespace.

The objects contained in the source schema are as follows:

SQL> select object_type, object_name from dba_objects where owner='MSC';
OBJECT_TYPE         OBJECT_NAME
------------------- ----------------------------------------------------
SEQUENCE            MSCSEQ
TABLE               USER_DATA
TABLE               USER_DOCUMENTS
INDEX               SYS_IL0000064679C00003$$
LOB                 SYS_LOB0000064679C00003$$
INDEX               PK_DATAID
INDEX               PK_DOCID

I will now export the schema MSC using exp:

[oracle@srvora01 dpdump]$ exp msc/Passw0rd file=exp_MSC.dmp log=exp_MSC.log consistent=y
Export: Release 11.2.0.3.0 - Production on Tue Aug 12 14:40:44 2014Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export done in AL32UTF8 character set and AL16UTF16 NCHAR character set. exporting pre-schema procedural objects and actions
. exporting foreign function library names for user MSC
. exporting PUBLIC type synonyms
. exporting private type synonyms
. exporting object type definitions for user MSC
About to export MSC's objects ...
. exporting database links
. exporting sequence numbers
. exporting cluster definitions
. about to export MSC's tables via Conventional Path ...
. . exporting table                      USER_DATA      99000 rows exported
. . exporting table                 USER_DOCUMENTS         25 rows exported
. exporting synonyms
. exporting views
. exporting stored procedures
. exporting operators
. exporting referential integrity constraints
. exporting triggers
. exporting indextypes
. exporting bitmap, functional and extensible indexes
. exporting posttables actions
. exporting materialized views
. exporting snapshot logs
. exporting job queues
. exporting refresh groups and children
. exporting dimensions
. exporting post-schema procedural objects and actions
. exporting statistics
Export terminated successfully without warnings.

I tried different ways to accomplish the tablespace remapping with imp. They are summarized below.

Revoke quota on USERS tablespace for the destination schema

I have read somewhere that a workaround could be to revoke UNLIMITED TABLESPACE (if granted) and any quota on USERS tablespace for the destination schema, and to grant UNLIMITED QUOTA on the target tablespace only (USER_DATA). This way, imp tool is supposed to import all objects into the schema default tablespace.

Let’s try this. I have created the destination schema with the right default tablespace and temporary tablespace and the required privileges:

SQL> create user DBI identified by Passw0rd default tablespace USER_DATA temporary tablespace TEMP quota unlimited on USER_DATA;
User created.
 SQL> grant create session, create table to DBI;
Grant succeeded.

The privilege UNLIMITED TABLESPACE is not granted to DBI user. Now, I will try to run the import:

[oracle@srvora01 dpdump]$ imp system/Passw0rd file=exp_MSC.dmp log=imp_to_DBI.log fromuser=msc touser=dbi
Import: Release 11.2.0.3.0 - Production on Tue Aug 12 14:53:47 2014
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export file created by EXPORT:V11.02.00 via conventional path
Warning: the objects were exported by MSC, not by you
export done in AL32UTF8 character set and AL16UTF16 NCHAR character set
. importing MSC's objects into DBI
. . importing table                    "USER_DATA"      99000 rows imported
IMP-00017: following statement failed with ORACLE error 1950:
 "CREATE TABLE "USER_DOCUMENTS" ("DOC_ID" NUMBER, "DOC_TITLE" VARCHAR2(25), ""
 "DOC_VALUE" BLOB)  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE(INI"
 "TIAL 65536 NEXT 1048576 MINEXTENTS 1 FREELISTS 1 FREELIST GROUPS 1 BUFFER_P"
 "OOL DEFAULT) TABLESPACE "USERS" LOGGING NOCOMPRESS LOB ("DOC_VALUE") STORE "
 "AS BASICFILE  (TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 RETENTIO"
 "N  NOCACHE LOGGING  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 FREELIS"
 "TS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT))"
IMP-00003: ORACLE error 1950 encountered
ORA-01950: no privileges on tablespace 'USERS'
Import terminated successfully with warnings.

The import has worked only for a part of the objects. As we can see, it seems that the table app_documents, containing a BLOB column, has not been imported. All objects associated to this table are not imported:

SQL> select object_type, object_name from dba_objects where owner='DBI';
OBJECT_TYPE         OBJECT_NAME
------------------- ----------------------------------------------------
TABLE               USER_DATA
SEQUENCE            MSCSEQ
INDEX               PK_DATAID

With no quota on the source tablespace, imp tool imports data in the target schema default tablespace, but LOBS are not supported.

Drop USERS tablespace prior to import data

Another method could be to drop the source tablespace, to be sure that the import tool does not try to import data in the USERS tablespace.

In this example, I will drop the USERS tablespace and try to import data again with the same command. Note that I have previously dropped the MSC and DBI schemas prior to dropping the USERS tablespace.

SQL> alter database default tablespace SYSTEM;
Database altered.
 
SQL> drop tablespace USERS including contents and datafiles;
Tablespace dropped.

I will now recreate the empty DBI schema, as shown in example 1:

SQL> create user DBI identified by Passw0rd default tablespace USER_DATA temporary tablespace TEMP quota unlimited on USER_DATA;
User created. 
 
SQL> grant create session, create table to DBI;
Grant succeeded.

Now let’s try to import the data again from the dump file:

oracle@srvora01:/u00/app/oracle/admin/DB11G/dpdump/ [DB11G] imp system/Passw0rd file=exp_MSC.dmp log=imp_to_DBI.log fromuser=msc touser=dbi
Import: Release 11.2.0.3.0 - Production on Tue Aug 12 17:03:50 2014
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export file created by EXPORT:V11.02.00 via conventional path
Warning: the objects were exported by MSC, not by you
import done in AL32UTF8 character set and AL16UTF16 NCHAR character set
. importing MSC's objects into DBI
. . importing table                    "USER_DATA"      99000 rows imported
IMP-00017: following statement failed with ORACLE error 959:
 "CREATE TABLE "USER_DOCUMENTS" ("DOC_ID" NUMBER, "DOC_TITLE" VARCHAR2(25), ""
 "DOC_VALUE" BLOB)  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE(INI"
 "TIAL 65536 NEXT 1048576 MINEXTENTS 1 FREELISTS 1 FREELIST GROUPS 1 BUFFER_P"
 "OOL DEFAULT) TABLESPACE "USERS" LOGGING NOCOMPRESS LOB ("DOC_VALUE") STORE "
 "AS BASICFILE  (TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 RETENTIO"
 "N  NOCACHE LOGGING  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 FREELIS"
 "TS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT))"
IMP-00003: ORACLE error 959 encountered
ORA-00959: tablespace 'USERS' does not exist
Import terminated successfully with warnings.

You can see that we have still have an error when importing the USER_DOCUMENTS table, but this time the error says “Tablespace USERS does not exist”. So, whatever we do, imp tool tries to import LOBS in the same tablespace. But other data is imported in the new DEFAULT tablespace of the schema.

We can say that imp has the same behavior no matter whether we revoke the quota on the source tablespace or whether we drop it. Clearly, LOBs are not supported by this method. But if you have a database with standard data, these two methods would help you to remap the tablespace at import time.

Pre-create objects in the new tablespace using the INDEXFILE option

Imp tool provides the option INDEXFILE which corresponds to the METADATA ONLY with expdp. There is one difference: while impdp directly creates object structures with METADATA_ONLY=Y in the database without any data, imp with the INDEXFILE option will just generate an sql file with all CREATE statements (tables, indexes etc.) and you will have to manually run this file with sqlplus to create the empty objects.

As you may expect (or not), this SQL file will allow you to change the tablespace name when objects have to be created, prior to importing data. The inconvenience is that several manual steps are involved in this workaround – the solution is described below.

1) Generate the SQL file

oracle@srvora01:/u00/app/oracle/admin/DB11G/dpdump/ [DB11G] imp system/Passw0rd file=exp_MSC.dmp log=imp_to_DBI.log fromuser=msc touser=dbi indexfile=imp_to_DBI.sql
Import: Release 11.2.0.3.0 - Production on Tue Aug 12 18:04:13 2014
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export file created by EXPORT:V11.02.00 via conventional path
Warning: the objects were exported by MSC, not by you
import done in AL32UTF8 character set and AL16UTF16 NCHAR character set
. . skipping table "USER_DATA"
. . skipping table "USER_DOCUMENTS"
Import terminated successfully without warnings.

2) Edit the SQL file

In this file, you will have two modifications to do. First, remove all REM keywords from the CREATE statements. All rows are created as a comment in the file. Then, change the tablespace name for all objects you want to create on a different tablespace.

This is how my SQL file looks like after the modifications:

oracle@srvora01:/u00/app/oracle/admin/DB11G/dpdump/ [DB11G] cat imp_to_DBI.sqlCREATE TABLE "DBI"."USER_DATA" ("DATA_ID" NUMBER, "DATA_VALUE"
 VARCHAR2(250)) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
 STORAGE(INITIAL 16777216 NEXT 1048576 MINEXTENTS 1 FREELISTS 1
 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USER_DATA" LOGGING
 NOCOMPRESS ;
 REM  ... 99000 rows
 CONNECT DBI;
 CREATE UNIQUE INDEX "DBI"."PK_DATAID" ON "USER_DATA" ("DATA_ID" ) PCTFREE
 10 INITRANS 2 MAXTRANS 255 STORAGE(INITIAL 2097152 NEXT 1048576 MINEXTENTS
 1 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USER_DATA"
 LOGGING ;
 ALTER TABLE "DBI"."USER_DATA" ADD CONSTRAINT "PK_DATAID" PRIMARY KEY
 ("DATA_ID") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
 STORAGE(INITIAL 2097152 NEXT 1048576 MINEXTENTS 1 FREELISTS 1
 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USER_DATA" LOGGING
 ENABLE ;
 CREATE TABLE "DBI"."USER_DOCUMENTS" ("DOC_ID" NUMBER, "DOC_TITLE"
 VARCHAR2(25), "DOC_VALUE" BLOB) PCTFREE 10 PCTUSED 40 INITRANS 1
 MAXTRANS 255 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1
 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USER_DATA"
 LOGGING NOCOMPRESS LOB ("DOC_VALUE") STORE AS BASICFILE (TABLESPACE
 "USER_DATA" ENABLE STORAGE IN ROW CHUNK 8192 RETENTION NOCACHE LOGGING
 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 FREELISTS 1 FREELIST
 GROUPS 1 BUFFER_POOL DEFAULT)) ;
 REM  ... 25 rows
 CREATE UNIQUE INDEX "DBI"."PK_DOCID" ON "USER_DOCUMENTS" ("DOC_ID" )
 PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE(INITIAL 65536 NEXT 1048576
 MINEXTENTS 1 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE
 "USER_DATA" LOGGING ;
 ALTER TABLE "DBI"."USER_DOCUMENTS" ADD CONSTRAINT "PK_DOCID" PRIMARY
 KEY ("DOC_ID") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 FREELISTS 1 FREELIST
 GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USER_DATA" LOGGING ENABLE ;
 ALTER TABLE "DBI"."USER_DOCUMENTS" ADD CONSTRAINT "FK_DOCID" FOREIGN
 KEY ("DOC_ID") REFERENCES "USER_DATA" ("DATA_ID") ENABLE NOVALIDATE ;
 ALTER TABLE "DBI"."USER_DOCUMENTS" ENABLE CONSTRAINT "FK_DOCID" ;

3) Execute the SQL file with SQL Plus

Simply use SQL Plus to execute the SQL file (the user DBI must exist prior to running the script):

oracle@srvora01:/u00/app/oracle/admin/DB11G/dpdump/ [DB11G] sqlplus / as sysdba @imp_to_DBI.sql
SQL*Plus: Release 11.2.0.3.0 Production on Tue Aug 12 18:13:14 2014
Copyright (c) 1982, 2011, Oracle.  All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Table created.
 
Enter password:
Connected.
 
Index created.
 
Table altered.
 
Table created.
 
Index created.
 
Table altered.
 
Table altered.
 
Table altered.

 

SQL> select object_type, object_name from user_objects;
OBJECT_TYPE         OBJECT_NAME
------------------- -----------------------------------
INDEX               PK_DATAID
TABLE               USER_DOCUMENTS
TABLE               USER_DATA
INDEX               SYS_IL0000064697C00003$$
LOB                 SYS_LOB0000064697C00003$$
INDEX               PK_DOCID

 

4) Disable all constraints

When importing data with imp or impdp tools, constraints are created and enabled at the end of the import. This allows Oracle to import data without taking into account any referential integrity constrainst. As we already have created empty objects with enabled constraints, we must manually disable the constraints before importing the data.

SQL> select 'ALTER TABLE ' || OWNER || '.' || TABLE_NAME || ' DISABLE CONSTRAINT ' || CONSTRAINT_NAME || ';' "SQL_CMD" from DBA_CONSTRAINTS WHERE OWNER='DBI';
SQL_CMD
-----------------------------------------------------------
ALTER TABLE DBI.USER_DOCUMENTS DISABLE CONSTRAINT FK_DOCID;
ALTER TABLE DBI.USER_DATA DISABLE CONSTRAINT PK_DATAID;
ALTER TABLE DBI.USER_DOCUMENTS DISABLE CONSTRAINT PK_DOCID;
 
SQL> ALTER TABLE DBI.USER_DOCUMENTS DISABLE CONSTRAINT FK_DOCID;
Table altered.
 
SQL> ALTER TABLE DBI.USER_DATA DISABLE CONSTRAINT PK_DATAID;
Table altered.
 
SQL> ALTER TABLE DBI.USER_DOCUMENTS DISABLE CONSTRAINT PK_DOCID;
Table altered.

5) Import the data with the IGNORE=Y option

Now we must import the data from the dump file using the IGNORE=Y option to ignore warnings about already existing objects. It will allow the imp tool to load data to the empty tables and indexes. Additionaly, I have set the CONSTRAINTS=N option because imp tried to enable the constraints after the import, which was generating an error…

oracle@srvora01:/u00/app/oracle/admin/DB11G/dpdump/ [DB11G] imp system/Passw0rd file=exp_MSC.dmp log=imp_to_DBI.log fromuser=msc touser=dbi ignore=y constraints=n
Import: Release 11.2.0.3.0 - Production on Tue Aug 12 19:43:59 2014
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export file created by EXPORT:V11.02.00 via conventional path
Warning: the objects were exported by MSC, not by you
import done in AL32UTF8 character set and AL16UTF16 NCHAR character set
. importing MSC's objects into DBI
. . importing table                    "USER_DATA"      99000 rows imported
. . importing table               "USER_DOCUMENTS"         25 rows imported
About to enable constraints...
Import terminated successfully without warnings.

All objects have been imported successfully:

SQL> select object_type, object_name from dba_objects where owner='DBI';
OBJECT_TYPE         OBJECT_NAME
------------------- ----------------------------------------------------
INDEX               PK_DATAID
TABLE               USER_DATA
TABLE               USER_DOCUMENTS
INDEX               SYS_IL0000064704C00003$$
LOB                 SYS_LOB0000064704C00003$$
INDEX               PK_DOCID
SEQUENCE            MSCSEQ

6) Enable constraints after the import

Constraints previously disabled must be enabled again to finish the import:

SQL> select constraint_name, status from dba_constraints where owner='DBI';CONSTRAINT_NAME                STATUS
------------------------------ --------
FK_DOCID                       DISABLED
PK_DOCID                       DISABLED
PK_DATAID                      DISABLED
 
SQL> select 'ALTER TABLE ' || OWNER || '.' || TABLE_NAME || ' ENABLE CONSTRAINT ' || CONSTRAINT_NAME || ';' "SQL_CMD" from DBA_CONSTRAINTS WHERE OWNER='DBI';
SQL_CMD
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ALTER TABLE DBI.USER_DOCUMENTS ENABLE CONSTRAINT FK_DOCID;
ALTER TABLE DBI.USER_DOCUMENTS ENABLE CONSTRAINT PK_DOCID;
ALTER TABLE DBI.USER_DATA ENABLE CONSTRAINT PK_DATAID;

Enable PRIMARY KEYS:

SQL> ALTER TABLE DBI.USER_DOCUMENTS ENABLE CONSTRAINT PK_DOCID;
Table altered.
 
SQL> ALTER TABLE DBI.USER_DATA ENABLE CONSTRAINT PK_DATAID;
Table altered.

And then FOREIGN KEY:

SQL> ALTER TABLE DBI.USER_DOCUMENTS ENABLE CONSTRAINT FK_DOCID;
Table altered.

Constraints are now enabled:

SQL> select constraint_name, status from dba_constraints where owner='DBI';CONSTRAINT_NAME                STATUS
------------------------------ --------
FK_DOCID                       ENABLED
PK_DATAID                      ENABLED
PK_DOCID                       ENABLED

 

We do not have to carry on quota on tablespaces here. As you can see, even if I have recreated my USERS tablespace prior to importing the data with the INDEXFILE option, the USERS tablespace contains no segment after the import:

SQL> select segment_name from dba_segments where tablespace_name='USERS';
no rows selected

Conclusion

Workaround 1 and 2, which are very similar, are simple and fast methods to remap tablespaces for import into a database without any LOB data. But in the presence of LOB data, the workaround 3 is the right method to successfully move every object of the database into the new database. The major constraint of this workaround is that you will have to manually edit an SQL file, which can become very fastidious if you have several hundred or thousand of objects to migrate…

It is also possible to first import the data in the same tablespac, and then use the MOVE statement to move all objects into the new tablespac. However, you may not be able to move ALL objects this way. Workaround 3 seems to be the best and “cleanest” way to do it.