Standard Operating Procedure

SQL Server → Oracle Database

Cross-engine migration from SQL Server (on-prem/VM/RDS) to Oracle Database (on-prem, Oracle Cloud, or RDS for Oracle). Covers schema conversion, type mapping, sequence generation, and post-migration validation.

Source: SQL Server 2016+  ·  Target: Oracle 12c+ / Oracle Cloud / RDS for Oracle  ·  Tool: MigrationBridge v1.3.0

📄 Overview

Migrating from SQL Server to Oracle Database is a deep cross-engine migration. Both are enterprise relational databases, but they differ significantly in dialect, object model, and runtime behavior. MigrationBridge automates the most critical conversion tasks while surfacing incompatibilities that require manual review.

Key Engine Differences

Area SQL Server Oracle Database MigrationBridge Handling
Query dialect T-SQL PL/SQL / SQL*Plus DDL converted; stored procedures flagged for manual rewrite
Auto-increment IDENTITY(1,1) SEQUENCE + trigger (12.1) or GENERATED AS IDENTITY (12.2+) Auto-creates SEQUENCE per IDENTITY column
Schema model Database > Schema > Table Schema = User (no separate schema namespace) Source schema maps to target Oracle user/schema
String types NVARCHAR, VARCHAR NVARCHAR2, VARCHAR2 Automatically remapped
Date/time DATETIME, DATETIME2, DATE TIMESTAMP, DATE DATETIME/DATETIME2 → TIMESTAMP; SQL Server DATE → Oracle DATE
Boolean BIT No native BOOLEAN in SQL (NUMBER(1,0)) BIT → NUMBER(1,0)
MAX types NVARCHAR(MAX), VARCHAR(MAX), VARBINARY(MAX) CLOB, CLOB, BLOB Automatically remapped; LOB data streamed in chunks
GUID UNIQUEIDENTIFIER VARCHAR2(36) Stored as hyphenated string
Spatial / hierarchy hierarchyid, geography, geometry No direct equivalent Columns SKIPPED — WARNING logged, not error
Case sensitivity Case-insensitive by default Identifiers UPPERCASE by default Tool wraps identifiers in double-quotes when needed
Max identifier length 128 chars 30 chars (12.1), 128 chars (12.2+) Names truncated and suffixed with hash if over limit
Stored procedures, views, functions, and triggers are NOT migrated. MigrationBridge copies table structures and data only. All programmatic objects must be manually rewritten in PL/SQL after migration.
Validated against AdventureWorks2019: 71 tables, 760,837 rows, 90 foreign keys. All tables migrated successfully. Columns of type hierarchyid and geography were skipped with WARNING.

🔒 Prerequisites — Source (SQL Server)

The account used by MigrationBridge to connect to SQL Server requires the following minimum permissions. Never use sa or sysadmin unless no other option exists.

Required Permissions

Create Migration Login (SQL Server)

-- Run on SQL Server as sysadmin
USE [master];

CREATE LOGIN [mb_reader]
  WITH PASSWORD = N'Str0ng!PassMB2024',
       DEFAULT_DATABASE = [AdventureWorks2019],
       CHECK_EXPIRATION = OFF,
       CHECK_POLICY = ON;

USE [AdventureWorks2019];

CREATE USER [mb_reader] FOR LOGIN [mb_reader];
ALTER ROLE [db_datareader] ADD MEMBER [mb_reader];

USE [master];
GRANT VIEW SERVER STATE TO [mb_reader];
GRANT VIEW ANY DATABASE TO [mb_reader];

Verify Source Connectivity

-- Confirm login and access
SELECT SUSER_NAME() AS current_login,
       DB_NAME()    AS current_database,
       GETDATE()    AS server_time;

-- Confirm table read access
SELECT TOP 1 * FROM [Person].[Person];

-- Confirm VIEW SERVER STATE
SELECT session_id, status, login_name
FROM   sys.dm_exec_sessions
WHERE  is_user_process = 1;

Check for Unsupported Column Types

-- Identify hierarchyid, geography, geometry columns before migration
SELECT
    t.name           AS table_name,
    c.name           AS column_name,
    tp.name          AS data_type,
    c.column_id
FROM   sys.columns         c
JOIN   sys.tables          t  ON t.object_id = c.object_id
JOIN   sys.types           tp ON tp.user_type_id = c.user_type_id
WHERE  tp.name IN ('hierarchyid', 'geography', 'geometry', 'xml', 'sql_variant')
  AND  t.is_ms_shipped = 0
ORDER BY t.name, c.column_id;
Columns of type hierarchyid and geography will be skipped during migration. MigrationBridge logs a WARNING for each skipped column. The containing table is still migrated — only the unsupported column is omitted. Review this list before proceeding.

ODBC Driver Check (Windows)

Get-OdbcDriver -Name "ODBC Driver*SQL Server*" | Select-Object Name, Platform

If no driver is listed, download and install ODBC Driver 17 for SQL Server from Microsoft's official download page before launching MigrationBridge.

🔧 Prerequisites — Target (Oracle Database)

Oracle Instant Client

MigrationBridge uses python-oracledb (formerly cx_Oracle) in Thick mode, which requires Oracle Instant Client libraries. Install Instant Client before running MigrationBridge.

# Download Oracle Instant Client Basic Package from:
# https://www.oracle.com/database/technologies/instant-client/downloads.html
# Extract to a stable path, e.g.:
#   Windows:  C:\oracle\instantclient_21_12
#   Linux:    /opt/oracle/instantclient_21_12

# Linux: add to LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/opt/oracle/instantclient_21_12:$LD_LIBRARY_PATH

# Windows: add the folder to PATH via System Properties > Environment Variables

Install Python Driver

# Recommended: python-oracledb (cx_Oracle successor, Oracle-maintained)
pip install python-oracledb

# Legacy alternative (still supported by MigrationBridge):
pip install cx_Oracle
MigrationBridge automatically detects whether python-oracledb or cx_Oracle is installed and uses the available driver. python-oracledb is preferred for Oracle 19c+ targets.

Test Oracle Connection via SQL*Plus

# SID-based connection
sqlplus mb_migrate/MigratePass2024!@//ora-host.example.com:1521/ORCL

# Service Name-based connection
sqlplus mb_migrate/MigratePass2024!@//ora-host.example.com:1521/ORCLPDB1

# Oracle Cloud (TLS / wallet)
sqlplus mb_migrate/MigratePass2024!@"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(HOST=adb.us-ashburn-1.oraclecloud.com)(PORT=1522))(CONNECT_DATA=(SERVICE_NAME=abc123_high.adb.oraclecloud.com)))"

Create Migration User (Oracle)

-- Connect as DBA (SYSDBA or privileged user)
CREATE USER mb_migrate IDENTIFIED BY "MigratePass2024!"
  DEFAULT TABLESPACE USERS
  TEMPORARY TABLESPACE TEMP
  QUOTA UNLIMITED ON USERS;

-- Minimum required privileges
GRANT CREATE SESSION   TO mb_migrate;
GRANT CREATE TABLE     TO mb_migrate;
GRANT CREATE SEQUENCE  TO mb_migrate;
GRANT CREATE TRIGGER   TO mb_migrate;
GRANT INSERT ANY TABLE TO mb_migrate;
GRANT DROP ANY TABLE   TO mb_migrate;

-- Allow gathering stats post-migration
GRANT EXECUTE ON DBMS_STATS TO mb_migrate;
For RDS for Oracle, connect as the master user (admin) to execute the CREATE USER and GRANT statements above. RDS does not support SYSDBA connections from external clients.

Verify Oracle Network Connectivity

# Test port reachability (Windows PowerShell)
Test-NetConnection -ComputerName ora-host.example.com -Port 1521

# Linux
nc -zv ora-host.example.com 1521

# tnsping (requires Oracle client)
tnsping //ora-host.example.com:1521/ORCL
1

Configure Connections

Open MigrationBridge and navigate to the Connections tab. Configure both the source (SQL Server) and the target (Oracle) connection profiles.

MigrationBridge v1.3.0
Dashboard
Connections
Migration
Logs

Source — SQL Server

SQL Server
sql-prod-01.corp.local
1433
AdventureWorks2019
mb_reader
••••••••••••
ODBC Driver 17 for SQL Server

Test Connection ✓ Connected — SQL Server 2019 (RTM-CU23)

Target — Oracle Database

Oracle
ora-db-01.corp.local
1521
SID
ORCL
mb_migrate
••••••••••••
python-oracledb (Thick)

Test Connection ✓ Connected — Oracle Database 19c Enterprise
SID vs Service Name: Use SID for traditional single-instance connections (e.g., ORCL). Use Service Name for PDB connections, RAC, and Oracle Cloud (e.g., ORCLPDB1 or abc123_high.adb.oraclecloud.com). When in doubt, ask your Oracle DBA. MigrationBridge builds the connection string as:
oracle+oracledb://user:pass@host:1521/SID (SID mode)
oracle+oracledb://user:pass@host:1521/?service_name=ORCLPDB1 (Service Name mode)

Connection String Formats

ModeConnection String
SID (on-prem / RDS) oracle+oracledb://mb_migrate:pass@ora-host:1521/ORCL
Service Name (PDB / RAC) oracle+oracledb://mb_migrate:pass@ora-host:1521/?service_name=ORCLPDB1
Oracle Cloud (Wallet / TLS) oracle+oracledb://mb_migrate:pass@/?dsn=alias_high + wallet path in config
RDS for Oracle oracle+oracledb://admin:pass@rds-endpoint.us-east-1.rds.amazonaws.com:1521/ORCL
2

Run Assessment

Click Run Assessment in MigrationBridge. The tool scans all tables in the source database and reports compatibility warnings. No data is moved during this phase.

Auto-Handled Conversions

MigrationBridge silently converts the following without user intervention:

SQL Server TypeOracle TypeNotes
IDENTITY(seed,incr)SEQUENCE + triggerOne sequence per IDENTITY column; seed and increment preserved
INTNUMBER(10)Standard integer
BIGINTNUMBER(19)Large integer
BITNUMBER(1,0)1=TRUE, 0=FALSE
FLOATFLOAT(53)IEEE 754 double precision
DATETIME / DATETIME2TIMESTAMPMillisecond precision preserved
SMALLDATETIMEDATEMinute precision
DATEDATEOracle DATE stores time component
NVARCHAR(n)NVARCHAR2(n)Direct mapping
VARCHAR(n)VARCHAR2(n)Direct mapping
NVARCHAR(MAX)CLOBStreamed in 1 MB chunks
VARCHAR(MAX)CLOBStreamed in 1 MB chunks
VARBINARY(MAX)BLOBBinary streamed in 1 MB chunks
UNIQUEIDENTIFIERVARCHAR2(36)Stored as lowercase hyphenated string
MONEY / SMALLMONEYNUMBER(19,4)Decimal precision preserved
DECIMAL(p,s) / NUMERIC(p,s)NUMBER(p,s)Direct mapping
TINYINTNUMBER(3)0–255
SMALLINTNUMBER(5)-32768 to 32767
CHAR(n)CHAR(n)Fixed-length
NCHAR(n)NCHAR(n)Fixed-length national char
REALFLOAT(24)Single precision
TIME(n)INTERVAL DAY TO SECOND(n)Time-of-day values
IMAGEBLOBLegacy binary large object
TEXTCLOBLegacy text large object
NTEXTCLOBLegacy national text

Columns That Are Skipped (WARNING)

The following column types have no Oracle equivalent and are SKIPPED:
  • hierarchyid — Oracle has no hierarchical node type. The column is omitted from the target table. A WARNING is logged per column.
  • geography / geometry — Oracle Spatial types differ fundamentally. Use Oracle SDO_GEOMETRY for these; manual migration required.
  • sql_variant — No Oracle equivalent. Column skipped with WARNING.
  • xml — Converted to CLOB with a WARNING noting that XML schema validation is not preserved.
These warnings do NOT block the migration. The table is created and populated without the skipped columns.

Assessment Output Sample

Assessment Report — AdventureWorks2019
[2026-07-12 09:14:02] INFO Assessment started — Source: AdventureWorks2019, Target: Oracle 19c (ORCL)
[2026-07-12 09:14:03] OK 71 tables found in source database
[2026-07-12 09:14:03] OK 90 foreign key constraints detected
[2026-07-12 09:14:04] WARN [HumanResources.Employee] Column "OrganizationNode" (hierarchyid) — will be SKIPPED
[2026-07-12 09:14:04] WARN [Person.Address] Column "SpatialLocation" (geography) — will be SKIPPED
[2026-07-12 09:14:04] OK 14 IDENTITY columns detected — sequences will be auto-created
[2026-07-12 09:14:05] OK 22 NVARCHAR(MAX) / VARCHAR(MAX) columns — will map to CLOB
[2026-07-12 09:14:05] OK 3 VARBINARY(MAX) columns — will map to BLOB
[2026-07-12 09:14:05] OK 8 UNIQUEIDENTIFIER columns — will map to VARCHAR2(36)
[2026-07-12 09:14:05] INFO Identifier length check: 0 names exceed 30 chars (Oracle 12.1 limit)
[2026-07-12 09:14:06] INFO Reserved word check: 2 columns auto-quoted ("LEVEL", "DATE")
[2026-07-12 09:14:06] OK Assessment complete — 2 warnings, 0 blockers. Ready to migrate.
Review all WARNINGs before proceeding. For skipped columns, assess whether the application can tolerate missing data or whether a manual migration strategy is needed for those columns post-migration.
3

Select Tables & Sync Mode

Navigate to the Migration tab. Select the tables to migrate and configure the sync mode.

Migration — Table Selection
Table Selection
Options
Schedule

Sync Mode

Full Copy (truncate & reload)
Incremental (CDC)
Schema Only

Tables Selected

Select All (71 tables)

HumanResources.Department  ·  HumanResources.Employee  ·  HumanResources.EmployeeDepartmentHistory  ·  Person.Address  ·  Person.AddressType  ·  Person.BusinessEntity  ·  Person.Contact  ·  Production.BillOfMaterials  ·  Production.Culture  ·  Production.Document  ·  Production.Product  ·  Production.ProductCategory  ·  Production.WorkOrder  ·  Purchasing.PurchaseOrderDetail  ·  Purchasing.PurchaseOrderHeader  ·  Sales.CreditCard  ·  Sales.Customer  ·  Sales.SalesOrder  ·  Sales.SalesOrderDetail  ·  ... and 51 more

Options

Drop and recreate target tables
Migrate foreign keys after data load
Create SEQUENCE for each IDENTITY column
Batch insert size: 1000 rows

Start Migration Save Configuration
Full Copy mode issues a TRUNCATE TABLE on each target table before loading. If target tables already contain data, it will be permanently deleted. Use Schema Only mode first on a fresh Oracle schema to validate DDL before loading data.
4

Run Migration

Click Start Migration. MigrationBridge processes tables in dependency order (parents before children), creates sequences for IDENTITY columns, loads all data, then applies foreign key constraints.

What Happens Internally

  1. Schema introspection: reads all column definitions, constraints, indexes from SQL Server system catalogs
  2. DDL generation: produces CREATE TABLE statements in Oracle syntax with mapped types
  3. SEQUENCE generation: one CREATE SEQUENCE per IDENTITY column, with matching seed and increment
  4. Trigger generation: BEFORE INSERT trigger to populate IDENTITY column from sequence (Oracle 12.1 compatibility mode)
  5. Data transfer: bulk INSERT in batches of 1,000 rows; LOB columns streamed separately
  6. FK creation: all foreign keys applied after all tables are loaded (avoids ordering issues)
  7. Row count validation: compares source and target row counts per table

Migration Log — AdventureWorks2019 Sample

Migration Log — AdventureWorks2019 → Oracle ORCL (mb_migrate)
[2026-07-12 09:20:01] INFO Migration started — 71 tables, Full Copy mode
[2026-07-12 09:20:02] OK DDL generated for 71 tables
[2026-07-12 09:20:03] OK CREATE SEQUENCE MB_SEQ_DEPARTMENT_DEPARTMENTID START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE
[2026-07-12 09:20:03] OK CREATE SEQUENCE MB_SEQ_EMPLOYEE_BUSINESSENTITYID START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE
[2026-07-12 09:20:03] OK ... 12 more sequences created (14 total)
[2026-07-12 09:20:04] OK 14 BEFORE INSERT triggers created for IDENTITY columns
[2026-07-12 09:20:05] OK [1/71] HumanResources.Department → 16 rows copied
[2026-07-12 09:20:06] OK [2/71] HumanResources.Shift → 3 rows copied
[2026-07-12 09:20:07] OK [3/71] Person.AddressType → 6 rows copied
[2026-07-12 09:20:08] OK [4/71] Person.BusinessEntity → 20,777 rows copied
[2026-07-12 09:20:09] WARN [5/71] HumanResources.Employee — column "OrganizationNode" (hierarchyid) SKIPPED
[2026-07-12 09:20:09] OK [5/71] HumanResources.Employee → 290 rows copied (1 column skipped)
[2026-07-12 09:20:11] WARN [9/71] Person.Address — column "SpatialLocation" (geography) SKIPPED
[2026-07-12 09:20:11] OK [9/71] Person.Address → 19,614 rows copied (1 column skipped)
[2026-07-12 09:20:45] OK [34/71] Sales.SalesOrderDetail → 121,317 rows copied
[2026-07-12 09:21:03] OK [51/71] Production.TransactionHistory → 113,443 rows copied
[2026-07-12 09:21:22] OK [71/71] Production.WorkOrderRouting → 67,131 rows copied
[2026-07-12 09:21:23] INFO All 71 tables loaded. Applying 90 foreign key constraints...
[2026-07-12 09:21:31] OK 90/90 foreign keys created successfully
[2026-07-12 09:21:32] INFO Row count validation in progress...
[2026-07-12 09:21:35] OK Row count validation PASSED — 760,837 / 760,837 rows confirmed across 71 tables
[2026-07-12 09:21:35] INFO Migration complete. Elapsed: 00:01:34 | Tables: 71 | Rows: 760,837 | Warnings: 2 | Errors: 0
Migration elapsed time depends on network latency, Oracle tablespace I/O, and LOB column volume. For large databases (>10 GB), consider running during a maintenance window and disabling target table logging (ALTER TABLE ... NOLOGGING) to improve throughput.

SEQUENCE Creation SQL (Oracle Syntax)

-- Example: auto-generated sequence for HumanResources.Department.DepartmentID (IDENTITY(1,1))
CREATE SEQUENCE MB_SEQ_DEPARTMENT_DEPARTMENTID
  START WITH 1
  INCREMENT BY 1
  MINVALUE 1
  MAXVALUE 9999999999999999999999999999
  NOCACHE
  NOCYCLE;

-- Companion BEFORE INSERT trigger (Oracle 12.1 / 12.2 compat)
CREATE OR REPLACE TRIGGER TRG_DEPARTMENT_DEPARTMENTID_BI
  BEFORE INSERT ON "DEPARTMENT"
  FOR EACH ROW
  WHEN (NEW."DepartmentID" IS NULL)
BEGIN
  :NEW."DepartmentID" := MB_SEQ_DEPARTMENT_DEPARTMENTID.NEXTVAL;
END;
/
On Oracle 12.2+, MigrationBridge uses GENERATED ALWAYS AS IDENTITY instead of a separate sequence + trigger when the target version is detected as 12.2 or higher. This reduces object count and is the Oracle-recommended approach for new schemas.
5

Verify Migration

After migration completes, run the following verification queries directly against the Oracle target database to confirm row counts, foreign keys, and data integrity.

Step 5a: Gather Fresh Statistics (Required for Accurate Row Counts)

-- Gather stats so USER_TABLES.NUM_ROWS is populated accurately
BEGIN
  DBMS_STATS.GATHER_SCHEMA_STATS(
    ownname          => 'MB_MIGRATE',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
    cascade          => TRUE,
    degree           => 4
  );
END;
/

Step 5b: Row Counts per Table

-- Query USER_TABLES for row counts (after stats gather)
SELECT
    table_name,
    num_rows,
    last_analyzed
FROM   user_tables
ORDER BY table_name;

-- More accurate live count (slower on large tables):
SELECT 'DEPARTMENT'        AS table_name, COUNT(*) AS row_count FROM "DEPARTMENT"        UNION ALL
SELECT 'EMPLOYEE'          AS table_name, COUNT(*) AS row_count FROM "EMPLOYEE"          UNION ALL
SELECT 'SALESORDERDETAIL'  AS table_name, COUNT(*) AS row_count FROM "SALESORDERDETAIL"  UNION ALL
SELECT 'PRODUCT'           AS table_name, COUNT(*) AS row_count FROM "PRODUCT"
ORDER BY 1;

Step 5c: Foreign Key Validation

-- List all FKs in the migrated schema
SELECT
    c.constraint_name,
    c.table_name,
    cc.column_name,
    c.r_constraint_name,
    c.status
FROM   user_constraints  c
JOIN   user_cons_columns cc ON cc.constraint_name = c.constraint_name
WHERE  c.constraint_type = 'R'
ORDER BY c.table_name, c.constraint_name;

-- Count: should equal 90 for AdventureWorks2019
SELECT COUNT(*) AS fk_count
FROM   user_constraints
WHERE  constraint_type = 'R';

-- Check for DISABLED constraints (should be 0)
SELECT constraint_name, table_name, status
FROM   user_constraints
WHERE  constraint_type = 'R'
  AND  status = 'DISABLED';

Step 5d: Spot-Check Data Samples

-- Verify a representative sample of data
SELECT * FROM "PRODUCT"     WHERE ROWNUM <= 5;
SELECT * FROM "EMPLOYEE"    WHERE ROWNUM <= 5;
SELECT * FROM "SALESORDER"  WHERE ROWNUM <= 5;

-- Confirm no NULLs in non-nullable columns (sample check)
SELECT COUNT(*) AS null_business_entity_id
FROM   "EMPLOYEE"
WHERE  "BusinessEntityID" IS NULL;
Do NOT cut over application traffic until row count validation passes 100%. If row counts differ, check the migration log for errors, verify batch commit settings, and re-run the affected tables individually using the Table Selection panel.
6

Post-Migration Tasks

After verifying row counts and FK integrity, complete the following Oracle-specific post-migration tasks before directing application traffic to the new target.

6a: Gather Schema Statistics

-- Full schema stats with histogram generation (run as mb_migrate or DBA)
BEGIN
  DBMS_STATS.GATHER_SCHEMA_STATS(
    ownname          => 'MB_MIGRATE',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
    method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
    cascade          => TRUE,
    degree           => 4,
    no_invalidate    => FALSE
  );
END;
/
Always gather statistics after a bulk data load. Without current statistics, Oracle's query optimizer will generate suboptimal execution plans, resulting in full table scans on large tables.

6b: Rebuild Indexes

-- List indexes in the migrated schema
SELECT index_name, table_name, status, blevel, leaf_blocks
FROM   user_indexes
ORDER BY table_name, index_name;

-- Rebuild any indexes with status = 'UNUSABLE'
BEGIN
  FOR idx IN (
    SELECT index_name FROM user_indexes WHERE status = 'UNUSABLE'
  ) LOOP
    EXECUTE IMMEDIATE 'ALTER INDEX ' || idx.index_name || ' REBUILD ONLINE';
  END LOOP;
END;
/

6c: Validate Sequences

-- Check all sequences and their current LAST_NUMBER
SELECT
    sequence_name,
    min_value,
    max_value,
    increment_by,
    last_number,
    cache_size,
    cycle_flag
FROM   user_sequences
ORDER BY sequence_name;

-- Advance each sequence to match the current MAX identity value in the target table
-- Example: DepartmentID max = 16 after migration; set sequence past 16
DECLARE
  v_max NUMBER;
  v_cur NUMBER;
  v_diff NUMBER;
BEGIN
  SELECT MAX("DepartmentID") INTO v_max FROM "DEPARTMENT";
  SELECT last_number INTO v_cur
  FROM   user_sequences
  WHERE  sequence_name = 'MB_SEQ_DEPARTMENT_DEPARTMENTID';

  v_diff := v_max - v_cur + 1;

  IF v_diff > 0 THEN
    EXECUTE IMMEDIATE
      'ALTER SEQUENCE MB_SEQ_DEPARTMENT_DEPARTMENTID INCREMENT BY ' || v_diff;
    SELECT MB_SEQ_DEPARTMENT_DEPARTMENTID.NEXTVAL INTO v_cur FROM DUAL;
    EXECUTE IMMEDIATE
      'ALTER SEQUENCE MB_SEQ_DEPARTMENT_DEPARTMENTID INCREMENT BY 1';
  END IF;
END;
/
After a full data load, each sequence's LAST_NUMBER starts at 1. If the application inserts new rows before sequences are advanced to match the migrated max values, primary key violations will occur. Always advance sequences before enabling application writes.

6d: Create Synonyms (if Schema Name Differs)

If the application connects as a different Oracle user than mb_migrate, create public or private synonyms so that the application user can access the migrated tables without qualifying them with the schema name.

-- Connect as DBA
-- Create public synonyms for all tables in mb_migrate schema
BEGIN
  FOR t IN (
    SELECT table_name FROM all_tables WHERE owner = 'MB_MIGRATE'
  ) LOOP
    BEGIN
      EXECUTE IMMEDIATE
        'CREATE OR REPLACE PUBLIC SYNONYM ' || t.table_name ||
        ' FOR MB_MIGRATE.' || t.table_name;
    EXCEPTION
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('Failed: ' || t.table_name || ' — ' || SQLERRM);
    END;
  END LOOP;
END;
/

6e: Grant Application User Access

-- Grant select/insert/update/delete to the application schema user
BEGIN
  FOR t IN (
    SELECT table_name FROM all_tables WHERE owner = 'MB_MIGRATE'
  ) LOOP
    EXECUTE IMMEDIATE
      'GRANT SELECT, INSERT, UPDATE, DELETE ON MB_MIGRATE.' ||
      t.table_name || ' TO APP_USER';
  END LOOP;
END;
/

6f: Final Checklist

TaskStatus
Row counts match source (760,837 rows)Required
90 FK constraints ENABLEDRequired
Statistics gathered on all tablesRequired
Indexes rebuilt (no UNUSABLE)Required
Sequences advanced past max migrated ID valuesRequired
Application connection string updated to Oracle DSNApp Team
Synonyms created for application userIf needed
Stored procedures rewritten in PL/SQLManual
Views recreated in Oracle SQL syntaxManual
UAT / smoke test passedApp Team

🔄 Type Conversion Map

Complete mapping of SQL Server data types to Oracle equivalents as applied by MigrationBridge v1.3.0.

SQL Server Type Oracle Type Notes / Caveats Status
IDENTITY(seed, incr) SEQUENCE + BEFORE INSERT trigger Seed and increment preserved; Oracle 12.2+ uses GENERATED AS IDENTITY Auto
INT NUMBER(10) -2,147,483,648 to 2,147,483,647 Auto
BIGINT NUMBER(19) ±9.2 × 1018 Auto
SMALLINT NUMBER(5) -32,768 to 32,767 Auto
TINYINT NUMBER(3) 0 to 255 Auto
BIT NUMBER(1,0) 1 = true, 0 = false; no native BOOLEAN in Oracle SQL Auto
DECIMAL(p,s) / NUMERIC(p,s) NUMBER(p,s) Direct precision and scale mapping Auto
MONEY NUMBER(19,4) 4 decimal places; currency storage Auto
SMALLMONEY NUMBER(10,4) Smaller range than MONEY Auto
FLOAT (53-bit) FLOAT(53) IEEE 754 double precision Auto
REAL (24-bit) FLOAT(24) IEEE 754 single precision Auto
DATETIME TIMESTAMP 3ms precision stored; Oracle TIMESTAMP has up to 9 fractional digits Auto
DATETIME2(n) TIMESTAMP(n) Fractional second precision preserved up to 6 digits Auto
SMALLDATETIME DATE Minute precision only; Oracle DATE stores to second Auto
DATE DATE Oracle DATE includes time component (00:00:00 set for date-only values) Auto
TIME(n) INTERVAL DAY(0) TO SECOND(n) Time-of-day interval mapping Auto
DATETIMEOFFSET TIMESTAMP WITH TIME ZONE Time zone offset preserved Auto
CHAR(n) CHAR(n) Fixed-length, byte semantics Auto
NCHAR(n) NCHAR(n) Fixed-length national character Auto
VARCHAR(n) VARCHAR2(n) Variable-length; Oracle VARCHAR2 max 4000 bytes (32767 with MAX_STRING_SIZE=EXTENDED) Auto
NVARCHAR(n) NVARCHAR2(n) Variable-length national character; Oracle max 2000 chars (4000 with EXTENDED) Auto
VARCHAR(MAX) CLOB Streamed in 1 MB chunks; application LOB APIs may differ Auto
NVARCHAR(MAX) CLOB Unicode text LOB; NCLOB available as alternative Auto
TEXT CLOB Legacy type; deprecated in SQL Server Auto
NTEXT CLOB Legacy national text; deprecated in SQL Server Auto
VARBINARY(n) RAW(n) Binary data up to 2000 bytes Auto
VARBINARY(MAX) BLOB Binary LOB; streamed in 1 MB chunks Auto
IMAGE BLOB Legacy binary; deprecated in SQL Server Auto
UNIQUEIDENTIFIER VARCHAR2(36) Stored as lowercase hyphenated string (e.g., 550e8400-e29b-41d4-a716-446655440000) Auto
XML CLOB XML schema validation not preserved; WARNING logged Warn
hierarchyid SKIPPED No Oracle equivalent; column omitted from target table; WARNING logged Skipped
geography SKIPPED Use Oracle SDO_GEOMETRY manually; column omitted; WARNING logged Skipped
geometry SKIPPED Use Oracle SDO_GEOMETRY manually; column omitted; WARNING logged Skipped
sql_variant SKIPPED No Oracle equivalent; column omitted; WARNING logged Skipped
ROWVERSION / TIMESTAMP RAW(8) 8-byte binary concurrency token; application logic must be rewritten Auto

Known Issues & Compatibility Notes

1. Oracle Reserved Words as Column Names

Oracle reserves words like DATE, LEVEL, ROWNUM, COMMENT, SIZE, OPTION, RESOURCE, SELECT. If a SQL Server column uses any of these names, MigrationBridge automatically wraps the identifier in double-quotes in all generated DDL and DML. The column is usable in Oracle but must always be quoted in queries.

Application queries that reference these columns must be updated to use double-quoted identifiers in Oracle. Example: SELECT "LEVEL", "DATE" FROM "MY_TABLE"

2. Oracle Identifier Case Sensitivity

Oracle stores unquoted identifiers in UPPERCASE. MigrationBridge preserves original SQL Server column/table names using double-quoted identifiers. This means:

3. Maximum Identifier Length (Oracle 12.1)

Oracle 12.1 and earlier enforce a 30-character maximum on object names (tables, columns, indexes, constraints, sequences). Oracle 12.2+ raised this to 128 characters.

4. Sequence Gaps After Reseed

If sequences were advanced during migration (due to retries or partial runs), the sequence LAST_NUMBER may be higher than the actual data maximum. This results in gaps in IDENTITY values after the migration. Gaps are generally harmless for surrogate keys but may affect applications that assume contiguous IDs.

To minimize gaps, always use a fresh Oracle schema for migration (no prior sequence state) and run migration in a single pass. Avoid retrying individual tables multiple times.

5. MERGE Statement Behavior Differences

SQL Server's MERGE and Oracle's MERGE have syntax and behavioral differences:

6. NULL Handling Differences

Oracle treats an empty string ('') as NULL. SQL Server distinguishes between NULL and ''. If your SQL Server data contains empty strings in VARCHAR columns, they will become NULL in Oracle.

Applications that insert empty strings into Oracle VARCHAR2 columns will store NULLs. This can break NOT NULL constraints and application logic that uses LEN() = 0 or similar checks. Audit your application for empty-string usage before cutover.

7. NOLOCK / READ UNCOMMITTED Hints

SQL Server's WITH (NOLOCK) and READ UNCOMMITTED have no Oracle equivalent. Oracle's multi-version read consistency provides consistent reads by default without dirty reads. All T-SQL query hints must be removed from application queries when ported to Oracle.

8. TOP vs ROWNUM / FETCH FIRST

SQL Server's SELECT TOP n must be rewritten as Oracle's WHERE ROWNUM <= n (12.1) or FETCH FIRST n ROWS ONLY (12.2+). MigrationBridge does not rewrite application queries; this is a manual task.

9. RDS for Oracle Limitations

📺 UI Behavior Notes

During an active migration, MigrationBridge displays a progress panel in the Migration tab. The following behaviors are expected and should not be interrupted:

MigrationBridge v1.3.0 — Migration in Progress
Migrating table 34 of 71 — Sales.SalesOrderDetail (121,317 rows)
Progress47%
34
Tables Done
357,241
Rows Copied
2
Warnings
Pause Cancel

Expected UI Behaviors During Migration

For migrations over a WAN or to Oracle Cloud, expect higher latency during the LOB streaming phase. Consider increasing the batch_size setting in migrationbridge.conf from 1000 to 5000 rows for non-LOB tables to improve throughput. Keep LOB batch size at 100 or below to avoid memory pressure.
All migration events are written to migrationbridge_sync_state_*.json in the application directory in real time. If the application crashes, re-open MigrationBridge and use Resume from State to continue from the last committed checkpoint.

MigrationBridge v1.3.0 · SQL Server → Oracle Database · User Guide · Troubleshooting