Move tables across databases. Schema, data and all.
SqlJam is a desktop import/export tool for relational and OLAP databases: MySQL, MariaDB, PostgreSQL, Oracle, SQL Server, Db2, H2, SQLite, Microsoft Access, DuckDB, ClickHouse and more. It copies tables (with indexes, constraints, sequences and partitions) directly into another database or into the same schema as copies, or saves them as a self-describing export package of SQL, Parquet or CSV files that can be imported later. Imports into a database run in one transaction which an error rolls back as a whole, and rows are inserted, updated or skipped by key.
| Problem | How SqlJam solves it |
|---|---|
| Different SQL dialects break hand-written migrations | One metadata model, a dialect per target: types, identifiers, defaults, identity and literals are translated |
| "Works on my 16, fails on their 9.4" | Version-aware dialects (Oracle11gDialect, PostgreSQL9Dialect, MySQL56Dialect, SQLServer2008Dialect …) chosen by detected or selected version |
| Tables arrive without keys, indexes or sequences | Copies primary keys, unique/regular indexes, foreign keys, comments, sequences, identity values and partitions |
Huge data.sql files nobody can open |
Split data files by size: orders.sql, orders_2.sql … and orders.csv, orders_2.csv … at 10 MB, orders.parquet, orders_2.parquet … at 256 MB, imported in the order of the parts |
| BLOB/CLOB literals explode scripts and hit 4000-byte limits | LOBs are stored as files (lob/<table>/000001_<column>.blob) and restored by primary key |
| Scripts lose context ("which DB? which version? complete?") | manifest.json records source, target, options, files (with SHA-256) and row counts, export and import are paired |
Timestamps shift, unsigned values overflow, bit becomes garbage |
Portable value pipeline: LocalDateTime, unsigned widening, bit strings, money, UUID, JSON, XML, arrays |
| Re-runs fail half way | Idempotent DDL (drop/create, IF NOT EXISTS, sequence restart), FKs created after data |
| Long jobs are a black box | Percentage progress, per-table progress, error log and cancel in the UI |
| Analytics teams want Parquet, not SQL | Parquet packages (ZSTD, Snappy, GZIP) through an embedded DuckDB, and Parquet files of other tools loaded into any table |
| Spreadsheets and text tools want CSV | CSV packages with your delimiter, quote, NULL text, header, encoding (UTF-8 with BOM for Excel, GBK and more) and date format, read back with the exact column types kept in manifest.json, and CSV files of other tools with detected delimiter and types |
| An import went wrong, now what? | One transaction by default: an error rolls back the whole import, or commit every N rows like other import tools. Skip rows with errors goes on and lists every skipped row in the log, which you can filter and save. Confirm before commit lets you review a successful import in one transaction, then Commit or Roll Back |
| Some rows exist already | Update or insert by key updates the rows of the same primary key, or of the columns you choose, and inserts the others. Skip existing by key keeps them and inserts the new rows only. Insert is the default |
| Warehouses live apart from OLTP databases | DuckDB and ClickHouse data sources, grouped as OLAP databases next to the relational ones |
| The rows come from a join or a report, not from one table | SQL Query editor with syntax highlighting: run the SQL, check the first rows, then export all rows of the query as a table into SQL, Parquet, CSV or another database |
| Only part of a table is needed | Data viewer query: columns, WHERE, GROUP BY and ORDER BY, then export the rows of the query. Missing target tables are created with the selected columns |
| A copy next to the original | Copy in the same schema with a table name such as {table}_copy. Keys, indexes and constraints get their own names and the source tables are protected |
| What is inside this package? | Package viewer: files with size and modified time, previews of manifest, SQL, LOB, Parquet and CSV files |
| Custom and modern types | PostgreSQL enums and domains, MySQL, MariaDB and Oracle vectors, DuckDB unions and fixed arrays, ClickHouse variants, maps and tuples |
flowchart LR
S[(Source DB)] --> O[XxxMetaDataOperations]
O --> T[Metadata tree<br/>catalog · schema · table · column · key · index · FK · partition · sequence]
T --> V[MetaDataVisitor]
V --> D[Target Dialect<br/>type + version subclass]
D --> DS[DdlScripter]
DS --> I[ImportExporter] --> TD[(Target DB)]
DS --> E[ScriptExporter] --> P[/Export package<br/>schema.sql · data*.sql · lob/ · manifest.json/]
DS --> PE[ParquetExporter · CsvExporter<br/>DuckDB workspace] --> PP[/Parquet or CSV package<br/>schema.sql · data/*.parquet or *.csv · manifest.json/]
P --> SI[ScriptImporter] --> TD
PP --> PI[ParquetImporter · CsvImporter] --> TD
| Component | Role |
|---|---|
Exporter |
Reads metadata, counts rows, pages rows (ordered by primary key) and feeds an ExportHandler |
ScriptExporter / ImportExporter |
Facades: export to a package / import into a database |
ScriptImporter |
Imports an export package (validates manifest.json, runs files in order, restores LOBs) |
ParquetExporter / ParquetImporter |
Parquet packages and Parquet files of other tools, written and read by an embedded DuckDB workspace |
CsvExporter / CsvImporter |
CSV packages (column types in manifest.json) and CSV files of other tools, through the same DuckDB workspace |
ManualTransaction |
Runs an import in one transaction which the user commits or rolls back. DDL which would commit the rows (MySQL, MariaDB, Oracle, H2) waits for the commit |
AbstractFileImporter |
Picks the importer of a package by the data format in its manifest.json |
TableQuery |
Columns, WHERE, GROUP BY and ORDER BY of the data viewer, used by exports per table |
Dialect + impexp.db.* |
Per-database SQL generation. Old versions are subclasses |
MetaDataOperations + impexp.db.* |
Per-database metadata fixes (comments, identity, generated columns, partitions, sequences) |
face.* |
JavaFX UI (AtlantaFX themes, Ikonli icons) |
Only Java 17+ is needed to run SqlJam. JavaFX and all JDBC drivers are inside the runnable jar. Building from source needs no Maven installation either, the Maven Wrapper (./mvnw) is included.
| Platform | Runnable jar | Launcher | Supported |
|---|---|---|---|
| Windows 10 / 11 (x64) | sqljam-<version>-win.jar |
sqljam.bat |
✅ |
| macOS Apple Silicon | sqljam-<version>-mac-aarch64.jar |
sqljam.sh |
✅ |
| macOS Intel | sqljam-<version>-mac.jar |
sqljam.sh |
✅ |
| Linux x64 (GTK 3) | sqljam-<version>-linux.jar |
sqljam.sh |
✅ |
| Database | Tested on | Supported from |
|---|---|---|
| MySQL | 9.6 | 5.5 (MySQL55/56/57Dialect) |
| PostgreSQL | 16 | 9.x (PostgreSQL9/10Dialect) |
| Oracle | 23ai Free | 11g (Oracle11g/12cDialect) |
| SQL Server | 2022 | 2008 (SQLServer2008Dialect) |
| Db2 for Linux, UNIX and Windows | 12.1 | 11.1 |
| MariaDB | 11.8 | 10.3 |
| H2 | 2.3 | 2.x |
| SQLite | 3.46 | 3.x |
Microsoft Access (.accdb, .mdb) |
2016 | 2000 |
| DuckDB (OLAP) | 1.5 | 1.x |
| ClickHouse (OLAP) | 26.9 | 24.x |
All JDBC drivers are bundled, no extra downloads.
git clone git@github.com:paganini2008/sqljam.git
cd sqljam
./mvnw -DskipTests package # Windows: mvnw.cmd -DskipTests package, output goes to bin/
bin/sqljam.sh # Windows: bin\sqljam.bat, or double click the jar of your platformbin/
├── sqljam-1.0.0-SNAPSHOT-win.jar # runnable jar of each platform,
├── sqljam-1.0.0-SNAPSHOT-mac-aarch64.jar # JavaFX and all JDBC drivers inside
├── sqljam-1.0.0-SNAPSHOT-mac.jar
├── sqljam-1.0.0-SNAPSHOT-linux.jar
├── sqljam.sh / sqljam.bat # launchers, pick the jar of the platform
├── sqljam.properties # configuration, edit and restart
├── sqljam.vmoptions # JVM options, one per line
├── sqljam.png # Dock icon of macOS
├── sqljam-tutorial.mp4 # tutorial video, export and import in under 3 minutes
├── sqljam-1.0.0-SNAPSHOT-sources.jar
└── sqljam-1.0.0-SNAPSHOT-javadoc.jar
Keep sqljam.properties and sqljam.vmoptions next to the runnable jar. Copy the folder anywhere and SqlJam still finds them, even when started by double click.
SqlJam starts with a splash screen while it loads the configuration, the data sources and the JDBC drivers:
- Create a data source on the login page and click Connect. The first start brings an Example Shop (H2) data source with a few e-commerce tables to try everything right away. Example on the login page or Help → Restore Example Database brings it back at any time.
- Right-click a database or schema → Export…
- Pick tables, choose SQL scripts, Parquet or CSV (folder) or Database (another data source, or a new one from the + button next to it), press Start. An import into a database runs in one transaction or commits every N rows (N is typed next to it), check Skip rows with errors to go on after bad rows and Confirm before commit to review it first, and choose Update or insert by key or Skip existing by key for rows which exist already.
- Open a table, narrow its rows on the Data tab with columns, WHERE, GROUP BY and ORDER BY, then Export… just those rows.
- SQL Query on the toolbar or a right-click opens an editor for the data source. Ctrl+Enter (⌘+Enter on macOS) runs the statement at the caret, Ctrl+Shift+Enter runs them all, then Export… sends all rows of the query through the same exits.
- Right-click a connected data source → Disconnect when you are done, its table tabs close with it. Exit sits at the right end of the toolbar. Help → About SqlJam shows the version, the home page, the repository and the author, and the GitHub icon at the bottom right opens the repository.
A short tutorial video walks through the example database: query rows, export into files, import the package into PostgreSQL, and copy the tables straight into SQL Server and Oracle.
| Login | Export wizard | Progress |
|---|---|---|
![]() |
![]() |
![]() |
| Data query | Package viewer | Parquet files |
|---|---|---|
![]() |
![]() |
![]() |
| SQL query | Package import | Light theme |
|---|---|---|
![]() |
![]() |
![]() |
Expected export package:
export/
├── schema.sql # tables, sequences, indexes, comments
├── data.sql # rows (data_2.sql, data_3.sql … when > 10 MB)
├── lob/
│ └── document/
│ ├── 000001_content.clob
│ └── 000001_attachment.blob
├── lob-manifest.json # LOB files → table / primary key / column
├── constraints.sql # foreign keys, applied after data
└── manifest.json # source, target, options, files (sha256), row counts
A Parquet package has the same layout with data/<table>.parquet instead of SQL data and LOB files, a CSV package with data/<table>.csv and a header row. LOB values stay inside the Parquet or CSV columns, manifest.json records "dataFormat": "PARQUET" or "CSV" (with the type of every CSV column), so an import picks the right importer by itself and reads the values back exactly.
Input: MySQL database shop, target dialect PostgreSQL 16, one file per table.
ScriptExporter exporter = new ScriptExporter(new File("export"), DataFileStrategy.FILE_PER_TABLE,
10 * 1024 * 1024);
Exporter.ExportConfiguration config = exporter.getConfiguration();
config.setDbType(DbType.MYSQL);
config.setUrl(DbType.MYSQL.getUrl("localhost", 3306, "shop"));
config.setUsername("root");
config.setPassword("secret");
config.setIncludedCatalogNames(new String[]{"shop"});
config.setIdReused(true); // keep identity values
exporter.setTargetDbType(DbType.POSTGRESQL); // generate PostgreSQL sql
exporter.setTargetSchemaName("public");
exporter.exportDdlAndData();
// The same tables as a Parquet package: data/orders.parquet ...
ParquetExporter parquet = new ParquetExporter(new File("export-parquet"));
// parquet.getConfiguration() is configured like the configuration above
parquet.setTargetDbType(DbType.POSTGRESQL); // schema.sql and constraints.sql for PostgreSQL
parquet.setCompression("ZSTD");
parquet.exportDdlAndData();
// The same tables as a CSV package: data/orders.csv, data/orders_2.csv ...
CsvExporter csv = new CsvExporter(new File("export-csv"));
csv.setDelimiter(";");
csv.setMaxFileSize(10 * 1024 * 1024);
csv.exportDdlAndData();Output: export/schema.sql, export/data/orders.sql, export/data/orders_2.sql, export/lob/…, export/manifest.json:
CREATE TABLE IF NOT EXISTS public.orders
(
id bigserial NOT NULL,
total numeric(12, 2) DEFAULT 0.00,
paid boolean DEFAULT true,
CONSTRAINT orders_pkey PRIMARY KEY (id)
);Input: Oracle 11g schema HR → SQL Server demo.hr (created if missing).
ImportExporter importer = new ImportExporter();
Exporter.ExportConfiguration source = importer.getExportConfiguration();
source.setDbType(DbType.ORACLE);
source.setUrl(DbType.ORACLE.getUrl("ora-host", 1521, "ORCL"));
source.setUsername("hr");
source.setPassword("secret");
source.setIncludedSchemaNames(new String[]{"HR"});
source.setIdReused(true);
ImportExportHandler.ImportConfiguration target = importer.getImportConfiguration();
target.setDbType(DbType.SQLSERVER);
target.setUrl(DbType.SQLSERVER.getUrl("mssql-host", 1433, "demo"));
target.setUsername("sa");
target.setPassword("secret");
target.setTargetSchemaName("hr"); // created automatically
importer.setExportListener(new ExportListener() {
@Override
public void onProgress(long processed, long total) {
System.out.printf("%d%%%n", processed * 100 / Math.max(total, 1));
}
});
importer.exportDdlAndData();Output: 0% … 100%. Tables, keys, indexes, comments and sequences in demo.hr. Identity columns continue from the imported max value.
Rows of a query and copies in the same schema use the same API:
// Only some columns and rows of EMPLOYEES, the target table is created with these columns
source.getTableQueries().put("EMPLOYEES", new TableQuery(List.of("EMPLOYEE_ID", "NAME", "SALARY"),
"SALARY > 1000", null, "SALARY DESC"));
// Copies next to the originals: EMPLOYEES_COPY, keys and indexes get their own names
target.setTableNamePattern("{table}_copy");try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://localhost:5432/demo", "postgres", "secret")) {
ScriptImporter importer = new ScriptImporter(connection, DbType.POSTGRESQL);
importer.importDirectory(new File("export"));
System.out.println(importer.getExecutedCount() + " statements, " + importer.getLobCount() + " LOBs");
}Output: ScriptImporter refuses packages whose status is not COMPLETED, whose target type differs, or whose files fail the SHA-256 check. AbstractFileImporter.forDirectory(dir, connection, dbType) returns the importer of the package (SQL, Parquet or CSV), and files of other tools are loaded by ParquetImporter or CsvImporter. A ManualTransaction keeps the import open until you commit or roll back:
ParquetImporter importer = new ParquetImporter(connection, DbType.POSTGRESQL);
long rows = importer.importFiles(List.of(new File("sales-2024.parquet")), "sales", ParquetImporter.Mode.CREATE);
try (ManualTransaction transaction = new ManualTransaction(connection, DbType.POSTGRESQL.isTransactionalDdl())) {
AbstractFileImporter packageImporter = AbstractFileImporter.forDirectory(dir, transaction.getConnection(),
DbType.POSTGRESQL);
packageImporter.importDirectory(dir);
transaction.commit(); // or transaction.rollback()
}| Source column | → PostgreSQL | → Oracle | → SQL Server | → MySQL |
|---|---|---|---|---|
MySQL bigint unsigned |
numeric(20, 0) |
NUMBER(20,0) |
decimal(20,0) |
same |
MySQL tinyint(1) |
boolean |
NUMBER(1) |
bit |
same |
PostgreSQL jsonb |
same | CLOB |
nvarchar(max) |
json |
PostgreSQL uuid |
same | VARCHAR2(36) |
uniqueidentifier |
char(36) |
Oracle NUMBER(9) / NUMBER(19) |
int4 / int8 |
same | int / bigint |
int / bigint |
SQL Server datetime2(7) |
timestamp (µs) |
TIMESTAMP(7) |
same | datetime(6) |
SQL Server tinyint (0 to 255) |
int2 |
NUMBER(5) |
same | smallint |
Db2 DECFLOAT(34) |
numeric |
NUMBER |
decimal(38,10) |
decimal(65,30) |
Db2 GRAPHIC(10) |
char(10) |
CHAR(10 CHAR) |
nchar(10) |
char(10) |
Db2 CHAR(4) FOR BIT DATA |
bytea |
RAW(4) |
binary(4) |
binary(4) |
Db2 XML |
xml |
CLOB |
xml |
longtext |
| PostgreSQL enum / domain | same (type created in the target schema) | VARCHAR2 / base type |
varchar / base type |
varchar / base type |
MySQL / Oracle VECTOR |
text |
same | nvarchar(max) |
same |
ClickHouse Nullable(String) / Array(T) |
text |
CLOB |
nvarchar(max) |
longtext |
DuckDB HUGEINT / UNION |
numeric(38, 0) / text |
NUMBER(38,0) / CLOB |
decimal(38,0) / nvarchar(max) |
decimal(38,0) / longtext |
Access CURRENCY / YESNO / OLE |
numeric(19, 4) / boolean / bytea |
NUMBER(19,4) / NUMBER(1) / BLOB |
decimal(19,4) / bit / varbinary(max) |
decimal(19,4) / tinyint(1) / longblob |
| Do | Why |
|---|---|
| Keep Keep identity values on | Foreign keys stay valid. Identities/sequences are reset to max + 1 |
| Pick the target version when exporting for an older server | e.g. 11.2 generates sequences + triggers instead of identity columns |
| Use one file per table for large exports | Re-run or inspect a single table easily |
| Import packages with SqlJam | Manifest validation, ordered files, LOB restore and FKs last |
| Use Parquet for analytics and lakes | Compact columnar files any engine reads, the schema still travels in schema.sql |
| Use CSV for spreadsheets and text tools | Opens anywhere, and SqlJam still restores the exact types from manifest.json |
| Keep one transaction for imports | An error rolls back everything, Confirm before commit shows the log and the row counts before the commit |
| Load again with Update or insert by key | Kept tables are updated by their primary keys, nothing is dropped |
| Shape a report in SQL Query first | The first rows show the columns and values, Export… then reads all rows by one cursor |
| Copy with a target table name | {table}_copy keeps the originals, a copy in the same schema without a new name is refused |
All settings live in sqljam.properties, placed next to the runnable jar in bin/.
| Layer (later wins) | Location |
|---|---|
| Built-in defaults | Coded in the application |
| Application file | sqljam.properties or conf/sqljam.properties next to the jar, or -Dsqljam.app.config=/path |
| User settings saved by the UI | ~/.sqljam/sqljam.properties, or -Dsqljam.config=/path |
| Property | Default | Description |
|---|---|---|
sqljam.home |
${user.home}/.sqljam |
Application data directory |
sqljam.connections.file |
${sqljam.home}/connections.json |
Saved data sources |
sqljam.ui.theme |
Primer Dark |
Primer/Nord/Cupertino Light & Dark, Dracula |
sqljam.ui.window.width / height |
1280 / 800 |
Main window size |
sqljam.banner.mode |
console |
Startup banner with the version: console, log or off |
sqljam.banner.location |
Custom banner file, ${sqljam.version} and ${java.version} are resolved |
|
sqljam.splash.enabled |
true |
Splash screen with the logo while starting |
sqljam.splash.min-duration |
1200 |
Minimum time of the splash screen in ms, so that it does not flash |
sqljam.ui.data.page-size |
200 |
Rows per page in the data viewer |
sqljam.export.page-size |
5000 |
Rows read per page when exporting, tuned by benchmark |
sqljam.export.lob-page-size |
100 |
Rows per page for tables with LOB columns, keeps memory low |
sqljam.import.batch-size |
1000 |
INSERT statements per batch when importing a package (Oracle uses PL/SQL blocks) |
sqljam.export.max-file-size |
10485760 |
Max bytes of a SQL or CSV data file before it is split (0 = unlimited) |
sqljam.export.parquet-max-file-size |
268435456 |
Max bytes of a Parquet file before the table is split, Parquet reads best in large files |
sqljam.export.csv-delimiter |
, |
Delimiter of CSV files: , ; | or \t |
sqljam.import.confirm-commit.reminder-minutes |
10 |
An import waiting for commit reminds you after these minutes, its transaction holds locks and log space (0 = off) |
sqljam.export.data-file-strategy |
SINGLE_FILE |
SINGLE_FILE or FILE_PER_TABLE |
sqljam.export.lob-separated |
true |
Write LOBs as files |
sqljam.pool.maximum-size |
10 |
HikariCP max pool size |
sqljam.pool.minimum-idle |
1 |
HikariCP min idle connections |
sqljam.pool.connection-timeout |
30000 |
ms |
sqljam.pool.idle-timeout |
300000 |
ms |
sqljam.pool.max-lifetime |
1800000 |
ms |
JVM options live in sqljam.vmoptions next to the runnable jar, one option per line. The launchers pass them to Java, and a jar started by double click restarts itself with them. JAVA_OPTS adds more and wins.
# sqljam.vmoptions (defaults)
-Xms256m
-Xmx2g
-XX:+UseG1GC
-Dfile.encoding=UTF-8
Export options (UI / ExportConfiguration):
| Option | Default | Description |
|---|---|---|
tableRecreated |
true |
Drop and recreate target tables |
idReused |
false (UI: true) |
Copy identity values and reset sequences |
indexIncluded / foreignKeyIncluded / commentIncluded / sequenceIncluded |
true |
Objects to copy |
failFast |
true |
Stop on the first data error, false skips the rows with errors and reports each of them |
identifierCase |
AUTO |
AUTO, KEEP, LOWER, UPPER |
dataFormat / compression |
SQL / ZSTD |
SQL, PARQUET or CSV packages, Parquet compression ZSTD, SNAPPY, GZIP, UNCOMPRESSED |
csvDelimiter |
, |
Delimiter of CSV packages |
writeMode / keyColumnNames |
INSERT |
UPSERT updates the rows of the same key (the primary key or chosen columns) and inserts the others, SKIP_EXISTING keeps them and inserts the others |
CsvOptions |
comma, ", UTF-8 |
Delimiter, quote, NULL text, header, encoding and date format of CSV files |
tableNamePattern |
Target table name, {table} is the source name, e.g. {table}_copy |
|
tableQueries |
Columns, WHERE and ORDER BY per table, e.g. rows narrowed in the data viewer | |
queries |
Free queries exported as tables, SQL by table name, e.g. the query of the SQL editor |
| Scenario (200,000 rows × 6 columns) | Time | Rows/s |
|---|---|---|
| H2 → Oracle 23ai | 2.1 s | 95.3k |
| H2 → export package (PostgreSQL, 32 MB, 4 files) | 2.9 s | 69.4k |
| H2 → PostgreSQL 16 | 3.2 s | 62.4k |
| H2 → MySQL 9.6 | 3.3 s | 60.7k |
| H2 → SQL Server 2022 | 5.0 s | 40.1k |
| Export package → PostgreSQL | 4.5 s | 44.5k |
Environment: Apple M2 Max, 32 GB, JDK 17. MySQL/PostgreSQL local, Oracle/SQL Server in Docker. Default settings.
| Design choice | Benefit |
|---|---|
| Rows paged by primary key | Stable, deterministic reads on every database |
| Tables copied one by one | Predictable load on production servers |
| Packages contain plain SQL | Readable, editable and portable. Direct import uses batched inserts for maximum speed |
| Topic | Link |
|---|---|
| Project site | paganini2008.github.io/sqljam |
| Blog | docs/blogger/sqljam-en.md |
| Developer guide | docs/developer-guide.md, the Java API for exports, imports, copies and queries |
| Change logs | change_logs |
| Core API | com.github.sqljam.impexp (Exporter, ScriptExporter, ImportExporter, ScriptImporter, ParquetExporter, ParquetImporter, CsvExporter, CsvImporter, ManualTransaction) |
FAQ
| Question | Answer |
|---|---|
| Can I export only some rows or columns? | Yes. Narrow the rows on the Data tab (columns, WHERE, ORDER BY) and press Export…, or set tableQueries. A missing target table is created with the selected columns |
| Can I export the rows of my own SQL? | Yes. Write it in SQL Query, run it, then Export…. Columns of tables keep their types, the rows are read once by a cursor. In code, put the SQL into queries |
| Can I copy a table inside the same database? | Yes. Choose the same data source and schema as the target and a table name such as {table}_copy |
| How are LOBs stored in Parquet? | Inside the Parquet columns (strings and binaries), no extra LOB files |
| How exact is CSV? | Exact. NULL is an empty field, an empty string is "", binaries are escaped, and every column is read back with its type from manifest.json |
| How are rows matched when they are updated or skipped? | By the primary key, or by the columns chosen in Key Columns. Choose the columns of a unique index of the target table: MySQL and MariaDB match rows by their unique indexes, PostgreSQL, SQLite and DuckDB require such an index. A table without primary key and chosen columns is inserted |
| Why does Db2 refuse a wide table? | Rows wider than a 4K page need a table space of larger pages. Create one once, e.g. CREATE BUFFERPOOL BP32K PAGESIZE 32K and CREATE TABLESPACE TS32K PAGESIZE 32K BUFFERPOOL BP32K, Db2 then places wide tables there by itself |
| Do names have to match in case? | No. An existing target table and its columns are matched without case, e.g. OrderId of the source writes the column orderid of PostgreSQL or ORDERID of Oracle |
| Which rows were skipped? | Each skipped row is in the log of the import with its key and its error. Errors only shows them, Save Log writes the whole log to a file |
| What does a roll back undo? | Everything on PostgreSQL, SQL Server, Db2, SQLite and DuckDB, tables included. MySQL, MariaDB, Oracle, H2 and Access commit DDL at once, there the created tables stay empty and keys and identity values are set after the commit |
| Can I export only the structure? | Yes. Rows are optional. Pick content Structure (ExportMode.DDL) for a package or a direct import. Tables, keys, indexes, comments, sequences and partitions are created without rows |
| Are partitioned tables kept? | Yes. The same database type creates the partitioning again with its partitions, bounds and rows: range, list, hash, key and subpartitions of MySQL and MariaDB (system time too), range, list, hash, default and nested partitions of PostgreSQL, range, list, hash, interval, automatic list, composite and reference partitions of Oracle, partition functions of SQL Server, range partitions of Db2 and partition keys of ClickHouse. Other databases get the tables with all rows. In the tree a partitioned table shows its partitioning next to its name and PostgreSQL partitions are listed under their table |
| Can I generate scripts for an older server? | Yes, choose the target version (e.g. Oracle 11.2, SQL Server 2008) and a compatible dialect is used |
| Can I keep the password out of disk? | Uncheck Remember password on the login page, it stays in memory for the session |
| How do I run the tests? | mvn verify, integration tests use local databases and are skipped when unreachable |
| Step | |
|---|---|
| Issues | github.com/paganini2008/sqljam/issues |
| Pull requests | Fork → branch → mvn verify → PR |
| Code style | Match existing code: getXxxStatement naming, Apache license header, class header javadoc, 4-space indent, no Spring |
| New database or version | Add XxxDialect / XxxMetaDataOperations in impexp.db, register in DbType, add a fixture in src/test/resources/<db>/ |
License: Apache License 2.0.












