---
title: "Migrate SQLite to Oracle in your browser"
description: "Migrate a SQLite database to Oracle: convert the .db file or its dump into a script with the same tables, keys and data, and a report of every change."
canonical: https://intosql.com/sqlite-to-oracle
last_updated: 2026-10-15
---

# Migrate SQLite to Oracle in your browser

Drop a SQLite database file (.db, .sqlite, .sqlite3) or the SQL that sqlite3's .dump writes, and download a script for Oracle with the same tables, keys, indexes and data. Each column gets the type its values fit, and every value Oracle can't hold as it is is listed in the report.

[SQLite to Oracle migration guide](https://intosql.com/docs/migrations/sqlite-to-oracle)

[SQLite to Oracle data types](https://intosql.com/docs/types/sqlite-to-oracle)

## What changes from SQLite to Oracle

Each row is a rule the converter applies, with the report line it writes when the rule changes something in your data.

| In SQLite | In Oracle | Report line |
| --- | --- | --- |
| declared types (any text: VARCHAR(255), DATETIME, BOOLEAN, JSON or none) | the type every value in the column fits |  |
| BOOLEAN, BOOL | NUMBER(1) with a CHECK of 0 and 1 |  |
| TEXT, VARCHAR(n), CHAR(n), CLOB | VARCHAR2(n CHAR) when every value fits, else CLOB |  |
| TEXT and VARCHAR(n) longer than 4000 bytes | VARCHAR2(4000 CHAR) when every value fits 4000 bytes (750 characters in a key), else CLOB | `text_as_lob` |
| DECIMAL(p,s), NUMERIC | the exact type when every value fits it, else a double |  |
| BLOB, and columns holding bytes | BLOB |  |
| DATE, DATETIME, TIMESTAMP holding ISO 8601 text | DATE or TIMESTAMP(p), by what the values hold |  |
| JSON holding JSON text | CLOB |  |
| Infinity in REAL columns | kept as BINARY_DOUBLE_INFINITY |  |
| INTEGER PRIMARY KEY, AUTOINCREMENT | GENERATED BY DEFAULT ON NULL AS IDENTITY, continuing after the highest id or sqlite_sequence's |  |
| COLLATE NOCASE | exact comparison | `case_insensitive_collation` |
| generated columns | virtual columns | `stored_as_virtual` |
| generated columns with functions IntoSQL doesn't write, and the || operator | a plain column | `generated_not_translated` |
| defaults with functions IntoSQL doesn't write (strftime, randomblob) | no default | `default_not_translated` |
| CHECK constraints | translated |  |
| CHECK constraints with functions IntoSQL doesn't write | not created | `check_skipped` |
| partial and expression indexes | not created | `index_skipped` |
| foreign keys (unenforced unless PRAGMA foreign_keys=ON) | after the data ENABLE NOVALIDATE, then validated |  |
| ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT | dropped | `foreign_key_action_unsupported` |
| empty strings and empty blobs | NULL | `empty_string_null` |
| foreign keys to tables the dump doesn't create | not created | `foreign_key_skipped` |
| primary keys holding NULL, and NOT NULL columns with values that become NULL | NOT NULL dropped | `not_null_relaxed` |
| views, triggers and virtual tables (FTS, R*Tree) | listed in the report | `not_converted_objects` |
| dumps without CREATE TABLE (--data-only) | types read from the values | `no_schema` |
| expressions in INSERT values other than the text functions dumps write | NULL | `expression_value` |
| NUL characters in text | kept |  |
| text that isn't valid UTF-8 | the bad bytes as the replacement character | `invalid_utf8_replaced` |
| text decoded twice (Ã±) | copied as it is | `mojibake_suspected` |

## Load the script into Oracle

The script creates the tables, copies the rows, then adds keys, indexes and foreign keys, so it loads fast and stops at the first error.

```shell
NLS_LANG=.AL32UTF8 sqlplus -S -L user@//localhost/mydb @sqlite.oracle.sql
```

Foreign keys are added ENABLE NOVALIDATE, so new rows are checked at once, and then validated. If an old row points to a row that doesn't exist, the script says which constraint and leaves it unvalidated, instead of failing half way.

For a large dump, run SQL*Plus on the same machine as the database. The script commits every 100 rows. The user that runs it needs CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER and CREATE PROCEDURE, and quota on its tablespace.

## Dump SQLite for the best result

The converter reads what the dump holds. These options keep more of your data in it:

- The database file itself converts as it is, read page by page in your browser. Close the app that writes to it first, so no change is left behind in its -wal file.
- sqlite3 app.db .dump > app.sql writes the same database as SQL, which converts too, as .sql or .sql.gz.
- DB Browser for SQLite writes that SQL with File, Export, Database to SQL file, and so does Python's iterdump().

## What isn't converted

Views and triggers are written in SQLite's own language. They are listed in the report by name, never dropped silently, so you can rewrite them for Oracle. Virtual tables, such as FTS5 and R*Tree, are listed too, and their shadow tables are left out.

## Questions about SQLite to Oracle

### Is my dump uploaded?

No. The converter runs in your browser and reads the dump from your disk in pieces, so it never leaves your computer. The desktop app and the command line convert on your computer too.

### How large can the dump be?

The converter never holds the whole dump in memory: it reads the file twice, by ranges, and writes the script as it goes. Multi-gigabyte dumps convert in the browser, in the desktop app and with the command line.

### Can I convert the .db file itself?

Yes. Drop the .db, .sqlite or .sqlite3 file: it is read in your browser and never uploaded. Text with NUL characters and every digit of a double arrive as stored, which a .dump can cut short.

### Which SQLite versions can the dump come from?

Database files from SQLite 3.0 on, in UTF-8 or UTF-16, and dumps from the sqlite3 shell's .dump or Python's iterdump(). Every test file and dump comes from sqlite3 3.31 to 3.54, STRICT and WITHOUT ROWID tables included, and is compared with its source cell by cell.

### How are column types decided when SQLite doesn't enforce them?

The declared type is a hint and the values decide: a column becomes NUMBER, BINARY_DOUBLE, DATE, TIMESTAMP, BLOB, VARCHAR2 or CLOB when every value fits it. Empty strings become NULL, as Oracle stores them, and the report counts them.

### Are INTEGER PRIMARY KEY and AUTOINCREMENT kept?

Yes. An INTEGER PRIMARY KEY becomes an identity column, every row keeps its id, and the next id continues after the highest one, or after sqlite_sequence's value with AUTOINCREMENT.

### What about views and triggers?

They are listed in the report by name and not converted, because each database writes them in its own language.

### Which Oracle versions does the script load on?

Oracle 19c and later. Every test dump loads on 21c and 23ai, stopping at the first error if anything goes wrong.

## From SQLite

- [SQLite to PostgreSQL](https://intosql.com/sqlite-to-postgresql)
- [SQLite to MySQL](https://intosql.com/sqlite-to-mysql)
- [SQLite to MariaDB](https://intosql.com/sqlite-to-mariadb)
- [SQLite to SQLite](https://intosql.com/sqlite-to-sqlite)
- [SQLite to SQL Server](https://intosql.com/sqlite-to-sql-server)

## Into Oracle

- [MySQL to Oracle](https://intosql.com/mysql-to-oracle)
- [MariaDB to Oracle](https://intosql.com/mariadb-to-oracle)
- [PostgreSQL to Oracle](https://intosql.com/postgresql-to-oracle)
- [SQL Server to Oracle](https://intosql.com/sql-server-to-oracle)
- [Oracle to Oracle](https://intosql.com/oracle-to-oracle)

## Guide and every pair

- [Oracle to SQLite](https://intosql.com/oracle-to-sqlite)
- [SQLite to Oracle migration guide](https://intosql.com/docs/migrations/sqlite-to-oracle)
- [SQLite to Oracle data types](https://intosql.com/docs/types/sqlite-to-oracle)
- [Every database pair](https://intosql.com/database-migration)
