SqlJam

Move tables across databases. Schema, data and all.

A desktop import/export tool that copies tables, indexes, constraints, sequences, partitions and rows between relational and OLAP databases, directly, as copies in the same schema, or through a self-describing SQL or Parquet export package you can import later.

MySQLMariaDBPostgreSQLOracle SQL ServerH2SQLite DuckDBClickHouse
SqlJam main window with the table structure of an employee table
Why SqlJam

Migrations fail on the details

INSERT statements are easy. Everything around them is not.

Dialects disagree

Types, identity columns, default values and literals differ in every database.

→ The target dialect translates them.

Old servers refuse new SQL

Oracle 11g has no identity, SQL Server 2008 no OFFSET, PostgreSQL 9 no partitions.

→ Version subclasses generate compatible SQL.

Keys and indexes go missing

Data arrives, but primary keys, foreign keys, sequences and comments do not.

→ Table-level objects move together.

Scripts become monsters

Gigabyte data.sql files and BLOB literals that break 4000-byte limits.

→ 10 MB parts and LOB files.

Values get corrupted

Shifted timestamps, overflowing unsigned numbers, garbled bits and money.

→ A portable value pipeline.

Features

Everything a table needs on the other side

Any-to-any

Every source/target combination, verified by tests.

Version-aware

Dialects picked by detected or selected server version.

Keys & constraints

Primary keys, indexes, foreign keys, comments and sequences.

Partitions

PostgreSQL, MySQL, Oracle and SQL Server partitioning preserved.

Export packages

SQL files, LOB files and manifest.json, split at 10 MB.

Verified imports

Status, target type and SHA-256 checked before running.

Progress you can see

Overall percentage, per-table progress, error log and cancel.

Dark by default

A modern JavaFX UI with 7 switchable themes.

Parquet packages

Columnar export packages and Parquet files of other tools, through an embedded DuckDB.

OLAP sources

DuckDB and ClickHouse next to the relational databases.

Query & export

Columns, WHERE, GROUP BY and ORDER BY in the data viewer, then export just those rows.

Copies in place

Copy tables inside the same schema with names like {table}_copy.

How it works

Read once, generate for any target

SqlJam builds a metadata tree of the source, renders it with the dialect of the target type and version, then streams rows to a database or an export package.

Architecture: source database, metadata tree, target dialect, then direct import or export package and package import
1

Metadata: per-database operations read tables, keys, indexes, comments, partitions and sequences.

2

Dialect: DbType.createDialect(major, minor) picks e.g. Oracle11gDialect.

3

Rows: counted, paged by primary key, normalized and written in batches, or written to Parquet by an embedded DuckDB.

Quick start

Running in two minutes

Java 17 is all you need on Windows, macOS and Linux. JavaFX and every JDBC driver are bundled.

bash
git clone git@github.com:paganini2008/sqljam.git && cd sqljam
./mvnw -DskipTests package       # Windows: mvnw.cmd, output goes to bin/
bin/sqljam.sh                    # Windows: bin\sqljam.bat, or double click the jar of your platform

Or use the API

java
// MySQL database → PostgreSQL export package
ScriptExporter exporter = new ScriptExporter(new File("export"), false);
Exporter.ExportConfiguration config = exporter.getConfiguration();
config.setDbType(DbType.MYSQL);
config.setUrl(DbType.MYSQL.getUrl("localhost", 3306, "shop"));
config.setUsername("root");
config.setPassword("secret");
exporter.setTargetDbType(DbType.POSTGRESQL);
exporter.exportDdlAndData();

Result

export/
├── schema.sql
├── data.sql            # data_2.sql … above 10 MB
├── lob/
│   └── document/000001_content.clob
├── lob-manifest.json
├── constraints.sql     # foreign keys, after data
└── manifest.json       # source, target, sha256, rows
Use cases

Ways to move a table

Export wizard

Pick tables, choose the target type and version, one file per table or a single data.sql, and whether LOBs go into files.

exporter.setTargetDbType(DbType.ORACLE);
exporter.setTargetVersion(11, 2);   // sequences + triggers
Progress dialog

Copy straight into another data source, or create one on the spot with the + button next to it. Target schemas are created, identities continue from the imported max value.

target.setDbType(DbType.SQLSERVER);
target.setTargetSchemaName("hr");   // created if missing
importer.exportDdlAndData();
Import package dialog

The manifest decides: only data sources of the exported target type are offered, files are checked by SHA-256 and run in order.

ScriptImporter importer = new ScriptImporter(connection, DbType.POSTGRESQL);
importer.importDirectory(new File("export"));
Table data viewer with a query

Browse databases, schemas and tables. Narrow the rows with columns, WHERE, GROUP BY and ORDER BY, then export just those rows. A missing target table is created with the selected columns.

source.getTableQueries().put("EMPLOYEES", new TableQuery(columns,
        "SALARY > 1000", null, "SALARY DESC"));
target.setTableNamePattern("{table}_copy");   // copies in the same schema
Package viewer with a Parquet file

Export packages of Parquet files, look inside them with sizes, times and previews, and load Parquet files of other tools into any table.

parquet.setCompression("ZSTD");
parquet.exportDdlAndData();   // data/<table>.parquet
importer.importFiles(files, "sales", ParquetImporter.Mode.CREATE);
Performance

Tens of thousands of rows per second

95.3krows/s · H2 → Oracle
100%cross-database pairs pass
578automated tests
91%line coverage
Throughput chart
Scenario (200,000 rows × 6 columns)TimeRows/s
H2 → Oracle 23ai2.1 s95.3k
H2 → export package (32 MB, 4 files)2.9 s69.4k
H2 → PostgreSQL 163.2 s62.4k
H2 → MySQL 9.63.3 s60.7k
H2 → SQL Server 20225.0 s40.1k
Export package → PostgreSQL4.5 s44.5k

Environment: Apple M2 Max, 32 GB, JDK 17 · MySQL and PostgreSQL local, Oracle and SQL Server in Docker · default settings.

Documentation

Learn more

Open source

Built in the open