> ## Documentation Index
> Fetch the complete documentation index at: https://www.cockroachlabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from Oracle

export const InternalLink = ({version, path = "", children, ...props}) => {
  let detectedVersion = version || "stable";
  if (typeof window !== 'undefined' && !version) {
    const match = window.location.pathname.match(/\/docs\/([^/]+)/);
    if (match) {
      detectedVersion = match[1];
    }
  }
  const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
  return <a href={`/docs/${detectedVersion}/${normalizedPath}`} {...props}>
      {children}
    </a>;
};

<Danger>
  The instructions on this page are outdated. Use the <InternalLink version="cockroachcloud" path="migrations-page?filters=oracle">MOLT Schema Conversion Tool</InternalLink> to convert an Oracle schema into a compatible CockroachDB schema, and a tool such as <InternalLink path="aws-dms">AWS Database Migration Service (DMS)</InternalLink> or <InternalLink path="qlik">Qlik</InternalLink> to migrate data from Oracle to CockroachDB.
</Danger>

This page has instructions for migrating data from Oracle into CockroachDB by <InternalLink path="import-into">importing</InternalLink> CSV files.

To illustrate this process, we use the following sample data and tools:

* [Swingbench OrderEntry data set](http://www.dominicgiles.com/swingbench.html), which is based on the `oe` schema that ships with Oracle Database 11g and Oracle Database 12c.
* [Oracle Data Pump](https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sutil/oracle-data-pump.html), which enables the movement of data and metadata from one database to another, and comes with all Oracle installations.
* [SQL\*Plus](https://docs.oracle.com/database/121/SQPUG/ch_three.htm), the interactive and batch query tool that comes with every Oracle Database installation.

<Tip>
  For best practices for optimizing import performance in CockroachDB, see <InternalLink path="import-performance-best-practices">Import Performance Best Practices</InternalLink>.
</Tip>

## Step 1. Export the Oracle schema

Using [Oracle's Data Pump Export utility](https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sutil/oracle-data-pump-export-utility.html), export the schema:

```shell theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
$ expdp user/password directory=datapump dumpfile=oracle_example.dmp content=metadata_only logfile=example.log
```

The schema is stored in an Oracle-specific format (e.g., `oracle_example.dmp`).

## Step 2. Convert the Oracle schema to SQL

Using [Oracle's Data Pump Import utility](https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sutil/datapump-import-utility.html), load the exported DMP file to convert it to a SQL file:

```shell theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
$ impdp user/password directory=datapump dumpfile=oracle_example.dmp sqlfile=example_sql.sql TRANSFORM=SEGMENT_ATTRIBUTES:N:table PARTITION_OPTIONS=MERGE
```

This SQL output will be used later, in [Step 7](#step-7-map-oracle-to-cockroachdb-data-types).

## Step 3. Export table data

You need to extract each table's data into a data list file (`.lst`). We wrote a simple SQL script (`spool.sql`) to do this:

```shell theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
$ cat spool.sql

SET ECHO OFF
SET TERMOUT OFF
SET FEEDBACK OFF
SET PAGESIZE 0
SET TRIMSPOOL ON
SET WRAP OFF
set linesize 30000
SET RECSEP OFF
SET VERIFY OFF
SET ARRAYSIZE 10000
SET COLSEP '|'

SPOOL '&1'

ALTER SESSION SET nls_date_format = 'YYYY-MM-DD HH24:MI:SS';
  # Used to set a properly formatted date for CockroachDB

SELECT * from &1;

SPOOL OFF

SET PAGESIZE 24
SET FEEDBACK ON
SET TERMOUT ON
```

<Note>
  In the example SQL script, `|` is used as a delimiter. Choose a delimiter that will not also occur in the rows themselves. For more information, see <InternalLink path="import-into#delimited-data-files">`IMPORT INTO`</InternalLink>.
</Note>

To extract the data, we ran the script for each table in SQL\*Plus:

```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
$ sqlplus user/password
```

```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
> @spool CUSTOMERS
  @spool ADDRESSES
  @spool CARD_DETAILS
  @spool WAREHOUSES
  @spool ORDER_ITEMS
  @spool ORDERS
  @spool INVENTORIES
  @spool PRODUCT_INFORMATION
  @spool LOGON
  @spool PRODUCT_DESCRIPTIONS
  @spool ORDERENTRY_METADATA
```

A data list file (`.lst`) with leading and trailing spaces is created for each table.

Exit SQL\*Plus:

```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
> EXIT
```

## Step 4. Configure and convert the table data to CSV

Each table's data list file needs to be converted to CSV and formatted for CockroachDB. We wrote a simple Python script (`fix-example.py`) to do this:

```python theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
$ cat fix-example.py

for lstfile in sys.argv[1:]:
  filename = lstfile.split(".")[0]

  with open(lstfile) as f:
    reader = csv.reader(f, delimiter="|")
    with open(filename+".csv", "w") as fo:
      writer = csv.writer(fo)
      for rec in reader:
        writer.writerow(map(string.strip, rec))
```

```shell theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
$ python3 fix-example.py CUSTOMERS.lst ADDRESSES.lst CARD_DETAILS.lst WAREHOUSES.lst ORDER_ITEMS.lst ORDERS.lst INVENTORIES.lst PRODUCT_INFORMATION.lst LOGON.lst PRODUCT_DESCRIPTIONS.lst ORDERENTRY_METADATA.lst
```

Format the generated CSV files to meet the CockroachDB's [CSV requirements](#csv-requirements).

### CSV requirements

You will need to export one CSV file per table, with the following requirements:

* Files must be in [valid CSV format](https://tools.ietf.org/html/rfc4180).
* Files must be UTF-8 encoded.
* If one of the following characters appears in a field, the field must be enclosed by double quotes:
  * delimiter (`,` by default)
  * double quote (`"`)
  * newline (`\n`)
  * carriage return (`\r`)
* If double quotes are used to enclose fields, then a double quote appearing inside a field must be escaped by preceding it with another double quote.  For example: `"aaa","b""bb","ccc"`
* If a column is of type <InternalLink path="bytes">`BYTES`</InternalLink>, it can either be a valid UTF-8 string or a <InternalLink path="sql-constants#hexadecimal-encoded-byte-array-literals">hex-encoded byte literal</InternalLink> beginning with `\x`. For example, a field whose value should be the bytes `1`, `2` would be written as `\x0102`.

### CSV configuration options

The following options are available to <InternalLink path="import-into">`IMPORT INTO ... CSV DATA`</InternalLink>:

* <InternalLink path="migrate-from-csv#column-delimiter">Column delimiter</InternalLink>
* <InternalLink path="migrate-from-csv#comment-syntax">Comment syntax</InternalLink>
* <InternalLink path="migrate-from-csv#skip-header-rows">Skip header rows</InternalLink>
* <InternalLink path="migrate-from-csv#null-strings">Null strings</InternalLink>
* <InternalLink path="migrate-from-csv#file-compression">File compression</InternalLink>

For usage examples, see <InternalLink path="migrate-from-csv#configuration-options">Migrate from CSV - Configuration Options</InternalLink>.

## Step 5. Compress the CSV files

Compress the CSV files for a faster import:

```shell theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
$ gzip CUSTOMERS.csv ADDRESSES.csv CARD_DETAILS.csv WAREHOUSES.csv ORDER_ITEMS.csv ORDERS.csv INVENTORIES.csv PRODUCT_INFORMATION.csv LOGON.csv PRODUCT_DESCRIPTIONS.csv ORDERENTRY_METADATA.csv
```

These compressed CSV files will be used to import your data into CockroachDB.

## Step 6. Host the files where the cluster can access them

Each node in the CockroachDB cluster needs to have access to the files being imported. There are several ways for the cluster to access the data; for more information on the types of storage <InternalLink path="import-into">`IMPORT INTO`</InternalLink> can pull from, see the following:

* <InternalLink path="use-cloud-storage">Use Cloud Storage</InternalLink>
* <InternalLink path="use-a-local-file-server">Use a Local File Server</InternalLink>

<Tip>
  We strongly recommend using cloud storage such as Amazon S3 or Google Cloud to host the data files you want to import.
</Tip>

## Step 7. Map Oracle to CockroachDB data types

Using the SQL file created in [Step 2](#step-2-convert-the-oracle-schema-to-sql), write <InternalLink path="create-table">`CREATE TABLE`</InternalLink> statements that match the schemas of the table data you're importing. Remove all Oracle-specific attributes and remap all Oracle data types.

For example, to create a `CUSTOMERS` table, issue the following statement in the CockroachDB SQL shell:

```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
CREATE TABLE customers (
  customer_id       DECIMAL
                    NOT NULL
                    PRIMARY KEY,
  cust_first_name   VARCHAR(40) NOT NULL,
  cust_last_name    VARCHAR(40) NOT NULL,
  nls_language      VARCHAR(3),
  nls_territory     VARCHAR(30),
  credit_limit      DECIMAL(9,2),
  cust_email        VARCHAR(100),
  account_mgr_id    DECIMAL,
  customer_since    DATE,
  customer_class    VARCHAR(40),
  suggestions       VARCHAR(40),
  dob               DATE,
  mailshot          VARCHAR(1),
  partner_mailshot  VARCHAR(1),
  preferred_address DECIMAL,
  preferred_card    DECIMAL,
  INDEX cust_email_ix (cust_email),
  INDEX cust_dob_ix (dob),
  INDEX cust_account_manager_ix (
      account_mgr_id
  )
 );
```

### Data type mapping

Use the table below for data type mappings:

| Oracle Data Type                                | CockroachDB Data Type                                                                                         |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `BLOB`                                          | <InternalLink path="bytes">`BYTES`</InternalLink> [<sup>1</sup>](#considerations)                             |
| `CHAR(n)`, `CHARACTER(n)`<br />n \< 256         | <InternalLink path="string">`CHAR(n)`, `CHARACTER(n)`</InternalLink>                                          |
| `CLOB`                                          | <InternalLink path="string">`STRING`</InternalLink> [<sup>1</sup>](#considerations)                           |
| `DATE`                                          | <InternalLink path="date">`DATE`</InternalLink>                                                               |
| `FLOAT(n)`                                      | <InternalLink path="decimal">`DECIMAL(n)`</InternalLink>                                                      |
| `INTERVAL YEAR(p) TO MONTH `                    | <InternalLink path="string">`VARCHAR`</InternalLink>, <InternalLink path="interval">`INTERVAL`</InternalLink> |
| `INTERVAL DAY(p) TO SECOND(s)`                  | <InternalLink path="string">`VARCHAR`</InternalLink>, <InternalLink path="interval">`INTERVAL`</InternalLink> |
| `JSON`                                          | <InternalLink path="jsonb">`JSON`</InternalLink> [<sup>2</sup>](#considerations)                              |
| `LONG`                                          | <InternalLink path="string">`STRING`</InternalLink>                                                           |
| `LONG RAW`                                      | <InternalLink path="bytes">`BYTES`</InternalLink>                                                             |
| `NCHAR(n)`<br />n \< 256                        | <InternalLink path="string">`CHAR(n)`</InternalLink>                                                          |
| `NCHAR(n)`<br />n > 255                         | <InternalLink path="string">`VARCHAR`, `STRING`</InternalLink>                                                |
| `NCLOB`                                         | <InternalLink path="string">`STRING`</InternalLink>                                                           |
| `NUMBER(p,0)`, `NUMBER(p)`<br />1 \<= p \< 5    | <InternalLink path="int">`INT2`</InternalLink> [<sup>3</sup>](#considerations)                                |
| `NUMBER(p,0)`, `NUMBER(p)`<br />5 \<= p \< 9    | <InternalLink path="int">`INT4`</InternalLink> [<sup>3</sup>](#considerations)                                |
| `NUMBER(p,0)`, `NUMBER(p)`<br />9 \<= p \< 19   | <InternalLink path="int">`INT8`</InternalLink> [<sup>3</sup>](#considerations)                                |
| `NUMBER(p,0)`, `NUMBER(p)`<br />19 \<= p \<= 38 | <InternalLink path="decimal">`DECIMAL(p)`</InternalLink>                                                      |
| `NUMBER(p,s)`<br />s > 0                        | <InternalLink path="decimal">`DECIMAL(p,s)`</InternalLink>                                                    |
| `NUMBER`, `NUMBER(\*)`                          | <InternalLink path="decimal">`DECIMAL`</InternalLink>                                                         |
| `NVARCHAR2(n)`                                  | <InternalLink path="string">`VARCHAR(n)`</InternalLink>                                                       |
| `RAW(n)`                                        | <InternalLink path="bytes">`BYTES`</InternalLink>                                                             |
| `TIMESTAMP(p)`                                  | <InternalLink path="timestamp">`TIMESTAMP`</InternalLink>                                                     |
| `TIMESTAMP(p) WITH TIME ZONE`                   | <InternalLink path="timestamp">`TIMESTAMP WITH TIMEZONE`</InternalLink>                                       |
| `VARCHAR(n)`, `VARCHAR2(n)`                     | <InternalLink path="string">`VARCHAR(n)`</InternalLink>                                                       |
| `XML`                                           | <InternalLink path="jsonb">`JSON`</InternalLink> [<sup>2</sup>](#considerations)                              |

<a id="considerations" />

* <sup>1</sup> `BLOBS` and `CLOBS` should be converted to <InternalLink path="bytes">`BYTES`</InternalLink>, or <InternalLink path="string">`STRING`</InternalLink> where the size is variable, but it's recommended to keep values under 1 MB to ensure performance. Anything above 1 MB would require refactoring into an object store with a pointer embedded in the table in place of the object.
* <sup>2</sup> `JSON` and `XML` types can be converted to <InternalLink path="jsonb">`JSONB`</InternalLink> using any XML to JSON conversion. `XML` must be converted to `JSONB` before importing into CockroachDB.
* <sup>3</sup> When converting `NUMBER(p,0)`, consider `NUMBER` types with Base-10 limits map to the Base-10 Limits for CockroachDB <InternalLink path="int">`INT`</InternalLink> types. Optionally, `NUMBERS` can be converted to <InternalLink path="decimal">`DECIMAL`</InternalLink>.

When moving from Oracle to CockroachDB data types, consider the following:

* <InternalLink path="online-schema-changes">Schema changes within transactions</InternalLink>
* <InternalLink path="online-schema-changes#no-online-schema-changes-between-executions-of-prepared-statements">Schema changes between executions of prepared statements</InternalLink>
* If <InternalLink path="jsonb">`JSON`</InternalLink> columns are used only for payload, consider switching to <InternalLink path="bytes">`BYTES`</InternalLink>.
* Max size of a single <InternalLink path="column-families">column family</InternalLink> (by default, the <InternalLink path="configure-replication-zones#range-max-bytes">maximum size of a range</InternalLink>).

For more information, refer to <InternalLink path="online-schema-changes">Online Schema Changes</InternalLink> and <InternalLink path="transactions">Transactions</InternalLink>.

### NULLs

For information on how CockroachDB handles `NULL`s, see <InternalLink path="null-handling">NULL Handling</InternalLink> and <InternalLink path="not-null">NOT NULL Constraint</InternalLink>.

### Primary key, constraints, and secondary indexes

Cockroach distributes a table by the <InternalLink path="primary-key">primary key</InternalLink> or by a default `ROWID` when a primary key is not provided. This also requires the primary key creation to be part of the table creation. Using the above [data type mapping](#data-type-mapping), refactor each table DDL to include the <InternalLink path="primary-key">primary key</InternalLink>, <InternalLink path="constraints">constraints</InternalLink>, and <InternalLink path="indexes">secondary indexes</InternalLink>.

For more information and examples, refer to the following:

* <InternalLink path="create-table">`CREATE TABLE` - Create a table</InternalLink>
* <InternalLink path="partitioning">Define Table Partitions</InternalLink>
* <InternalLink path="constraints#supported-constraints">Constraints - Supported constraints</InternalLink>

### Privileges for users and roles

The Oracle privileges for <InternalLink path="create-user">users</InternalLink> and <InternalLink path="create-role">roles</InternalLink> must be rewritten for CockroachDB. Once the CockroachDB cluster is <InternalLink path="security-reference/security-overview">secured</InternalLink>, CockroachDB follows the same <InternalLink path="authorization">role-based access control</InternalLink> methodology as Oracle.

## Step 8. Import the CSV

Use <InternalLink path="import-into">`IMPORT INTO`</InternalLink> to import data into each table created in [Step 7](#step-7-map-oracle-to-cockroachdb-data-types).

For example, to import the data from `CUSTOMERS.csv.gz` into an existing `CUSTOMERS` table, issue the following statement in the CockroachDB SQL shell:

```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
IMPORT INTO CUSTOMERS
  CSV DATA ('https://your-bucket-name.s3.us-east-2.amazonaws.com/CUSTOMERS.csv.gz')
  WITH delimiter = e'\t',
   "nullif" = '',
   decompress = 'gzip';
```

```
       job_id       |  status   | fraction_completed |  rows  | index_entries | system_records |  bytes
--------------------+-----------+--------------------+--------+---------------+----------------+----------
 381866942129111041 | succeeded |                  1 | 300024 |             0 |              0 | 13258389
(1 row)
```

Then add the <InternalLink path="computed-columns">computed columns</InternalLink>, <InternalLink path="alter-table#add-constraint">constraints</InternalLink>, and <InternalLink path="create-index">function-based indexes</InternalLink>. For example:

```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
> UPDATE CUSTOMERS SET credit_limit = 50000 WHERE credit_limit > 50000;
  ALTER TABLE CUSTOMERS ADD CONSTRAINT CUSTOMER_CREDIT_LIMIT_MAX CHECK (credit_limit <= 50000);
  ALTER TABLE CUSTOMERS ADD COLUMN LOW_CUST_LAST_NAME STRING AS (lower(CUST_LAST_NAME)) STORED;
  ALTER TABLE CUSTOMERS ADD COLUMN LOW_CUST_FIRST_NAME STRING AS (lower(CUST_FIRST_NAME)) STORED;
  CREATE INDEX CUST_FUNC_LOWER_NAME_IX on CUSTOMERS (LOW_CUST_LAST_NAME,CUST_FIRST_NAME);
```

Repeat the preceding steps for each CSV file you want to import.

## Step 9. Refactor application SQL

The last phase of the migration process is to change the [transactional behavior](#transactions-locking-and-concurrency-control) and [SQL dialect](#sql-dialect) of your application.

### Transactions, locking, and concurrency control

Both Oracle and CockroachDB support <InternalLink path="transactions">multi-statement transactions</InternalLink>, which are atomic and guarantee ACID semantics. However, CockroachDB operates under <InternalLink path="demo-serializable">`SERIALIZABLE`</InternalLink> isolation by default, while Oracle defaults to <InternalLink path="read-committed">`READ COMMITTED`</InternalLink>, which can create both <InternalLink path="read-committed#non-repeatable-reads-and-phantom-reads">non-repeatable reads and phantom reads</InternalLink> when a transaction reads data twice. It is typical that Oracle developers will use `SELECT FOR UPDATE` to work around `READ COMMITTED` concurrency anomalies. Both the <InternalLink path="read-committed">`READ COMMITTED`</InternalLink> isolation level and the <InternalLink path="select-for-update">`SELECT FOR UPDATE`</InternalLink> statement are supported in CockroachDB.

Regarding locks, Cockroach utilizes a <InternalLink path="architecture/transaction-layer#latch-manager">lightweight latch</InternalLink> to serialize access to common keys across concurrent transactions. Oracle and CockroachDB transaction control flows only have a few minor differences; for more details, refer to <InternalLink path="transactions#sql-statements">Transactions - SQL statements</InternalLink>.

Because CockroachDB does not allow serializable anomalies under `SERIALIZABLE` isolation, <InternalLink path="begin-transaction">transactions</InternalLink> may experience deadlocks or <InternalLink path="performance-best-practices-overview#transaction-contention">read/write contention</InternalLink>. This is expected during concurrency on the same keys. These can be addressed with either <InternalLink path="transactions#automatic-retries">automatic retries</InternalLink> or <InternalLink path="transaction-retry-error-reference#client-side-retry-handling">client-side transaction retry handling</InternalLink>.

### SQL dialect

Cockroach is ANSI SQL compliant with a PostgreSQL dialect, which allows you to use <InternalLink path="install-client-drivers">native drivers</InternalLink> to connect applications and ORMs to CockroachDB. CockroachDB’s <InternalLink path="architecture/sql-layer#sql-api">SQL layer</InternalLink> supports full relational schema and SQL (similar to Oracle).

You will have to refactor Oracle SQL and functions that do not comply with [ANSI SQL-92](https://wikipedia.org/wiki/SQL-92) in order to work with CockroachDB. For more information about the <InternalLink path="sql-grammar">Cockroach SQL Grammar</InternalLink> and a <InternalLink path="sql-feature-support">SQL comparison</InternalLink>, see below:

* <InternalLink path="performance-best-practices-overview">SQL best practices</InternalLink>

* <InternalLink path="common-table-expressions">Common table expressions (CTE)</InternalLink>

* `DUAL` table

  Oracle requires use of the `DUAL` table, as Oracle requires a `SELECT ... FROM`. In CockroachDB, all reference to the `DUAL` table should be eliminated.

* <InternalLink path="functions-and-operators#string-and-byte-functions">Function call syntax</InternalLink>

* <InternalLink path="cost-based-optimizer#join-hints">Hints</InternalLink>

  See also: <InternalLink path="table-expressions#force-index-selection">Table Expressions - Force index selection</InternalLink>

* <InternalLink path="joins">Joins</InternalLink>

  CockroachDB supports <InternalLink path="joins#hash-joins">`HASH`</InternalLink>, <InternalLink path="joins#merge-joins">`MERGE`</InternalLink>, and <InternalLink path="joins#lookup-joins">`LOOKUP`</InternalLink> joins. Oracle uses the `+` operator for `LEFT` and `RIGHT` joins, but CockroachDB uses the ANSI join syntax.

* <InternalLink path="create-sequence">Sequences</InternalLink>

  Sequences in CockroachDB do not require a trigger to self-increment; place the sequence in the table DDL:

  ```
  > CREATE TABLE customer_list (
      id INT PRIMARY KEY DEFAULT nextval('customer_seq'),
      customer string,
      address string
    );
  ```

* <InternalLink path="subqueries">Subqueries</InternalLink>

* `SYSDATE`

  CockroachDB does not support `SYSDATE`; however, it does support date and time with the following:

  ```
  > SELECT transaction_timestamp(), clock_timestamp();
  ```

  ```
  > SELECT current_timestamp
  ```

  ```
  > SELECT now();
  ```

* <InternalLink path="window-functions">Window functions</InternalLink>

## See also

* <InternalLink path="import-into">`IMPORT INTO`</InternalLink>
* <InternalLink path="import-performance-best-practices">Import Performance Best Practices</InternalLink>
* <InternalLink path="migrate-from-csv">Migrate from CSV</InternalLink>
* <InternalLink version="molt" path="migrate-to-cockroachdb?filters=mysql">Migrate from MySQL</InternalLink>
* <InternalLink version="molt" path="migrate-to-cockroachdb">Migrate from PostgreSQL</InternalLink>
* <InternalLink path="take-full-and-incremental-backups">Back Up and Restore Data</InternalLink>
* <InternalLink path="cockroach-sql">Use the Built-in SQL Client</InternalLink>
* <InternalLink path="cockroach-commands">`cockroach` Commands Overview</InternalLink>
