Lightweight, GUI-based table shuttle between two relational DBs (e.g., Oracle → PostgreSQL) with chunked inserts and error-skipping.
 
DataShuttle is a PyQt5 application that pulls rows from a source (Origin) database and inserts them into a destination database, assuming identical table structures. It focuses on practicality:
- Chunked migration (default 10,000 rows per batch)
- Skip-on-error per row when needed
- Non-blocking UI (QThread-based worker)
- Instant Test Connection in Settings
- Preset Save/Load to quickly reuse connection & query configs
- CSV Export (Origin) with UTF-8
- 
Two Connections (Connection 1 / Connection 2) 
 Oracle or PostgreSQL for each side. Auto-default ports by DB type.
- 
Origin / Destination Mapping 
 Separate inputs for OriginSCHEMA, TABLESand DestinationSCHEMA, TABLES. If destination names are blank, origin names are used. WHERE applies to Origin only.
- 
Chunked Inserts + Error Skips 
 Streams SELECT from Origin and bulk-inserts to Destination (10,000 rows per chunk). If a chunk fails, it retries per row and skips rows that still fail, logging errors with row index.
- 
Cross-DB Identifier Handling 
 Oracle identifiers are handled without breaking (e.g.,UPDATED_ATvs"updated_at"). The app selects with proper aliases to keep mapping stable.
- 
Settings Dialog - DB Type (Oracle / PostgreSQL)
- Protocol (TCP / TCPS-SSL placeholder)
- Host / Port (auto default by DB type)
- Service/DB (Oracle: SERVICE_NAME/SID, PostgreSQL: database name)
- Test Connection… button
 
- 
Preset Save/Load 
 One-click export/import of JSON (saved as.txtor.json) including:
 connection_1/2config, Origin schema/tables/where, Destination schema/tables.
- 
CSV Export (Origin) 
 Re-run the same Origin query and stream results to CSV (UTF-8 with BOM:utf-8-sig).
 Multi-table export saves one file per table to the selected folder.
data_shuttle/
  ├─ gui.py                 # UI event handlers, QThread worker wiring
  ├─ ui_setup.py            # Pure UI layout (widgets only)
  ├─ utils.py               # DB engines, counting, streaming select→insert, CSV export
  └─ dialog/
      └─ settings_dialog.py # Settings modal with Test Connection
- Python 3.10+
- Windows/macOS/Linux (desktop environment)
- Packages:
- PyQt5
- SQLAlchemy>=2.0
- oracledb(for Oracle)
- psycopg[binary](for PostgreSQL)
- PyInstaller(for packaging)
- pandas(optional, CSV helpers)
 
- 
Clone & Install pip install -r requirements.txt 
- 
Run python .\main.py
- 
Build Executable (Windows) pyinstaller --onefile --windowed --icon=favicon.ico --hidden-import=psycopg --hidden-import=psycopg_pool --hidden-import=sqlalchemy.dialects.oracle --hidden-import=sqlalchemy.dialects.postgresql.psycopg --collect-all=psycopg_binary --collect-all=oracledb --collect-all=cryptography main.py 
- Open Settings (⚙) → Choose DB type (Oracle/PostgreSQL), fill Host/Port/Service/DB/ID/Password.
- Test Connection… to verify credentials on each tab (Connection 1 / Connection 2).
- Fill Origin (SCHEMA,TABLES) and Destination (SCHEMA,TABLES).- Leave Destination fields empty to mirror Origin names.
- WHERE is Origin-only (write conditions without the WHEREkeyword).
 
- Start Migration
- Console shows logs; the Result table shows Step/Detailprogress (chunk successes, per-row errors).
 
- Console shows logs; the Result table shows 
- CSV Export (Origin) to save the Origin query results (UTF-8 with BOM).
- Save Preset (top-left): dumps a JSON like:
{ "version": 1, "settings": { "connection_1": { "db_type": "Oracle", "host": "127.0.0.1", "port": 1521, "service_or_db": "ORCL", "user": "scott", "password": "tiger" }, "connection_2": { "db_type": "PostgreSQL", "host": "127.0.0.1", "port": 5432, "service_or_db": "devdb", "user": "dev", "password": "devpw" } }, "origin": { "schema": "DATASHUTTLE", "tables": "T1,T2", "where": "status='A'" }, "destination": { "schema": "DEV_DS", "tables": "T1_DST,T2_DST" } }
- Load Preset: restores both connections + Origin/Destination/WHERE.
Security Note: Preset files contain credentials. Please keep them in a secure location.
- 
ModuleNotFoundError: oracledb / psycopg
 Install DB drivers:pip install oracledb "psycopg[binary]"
- 
Oracle ORA-00904 invalid identifier
 The app handles identifier casing by selecting with aliases; ensure actual column names exist and table structures match.
- 
Korean (한글) breaks in CSV 
 Files are written as UTF-8 with BOM (utf-8-sig) for Excel compatibility. If your environment still breaks, trycp949.
- 
PyInstaller missing dialects 
 Add hidden imports:
 --hidden-import sqlalchemy.dialects.oracle --hidden-import sqlalchemy.dialects.postgresql.psycopg
This project is licensed under the MIT License.
See the LICENSE file for details.