Migrating from Oracle to SQL Server: A Practical Checklist

Migrate Oracle workloads to SQL Server — data type mapping, PL/SQL conversion, SSMA tooling, and validation strategies

JusDB Team
February 23, 2026
Updated June 20, 2026
9 min read

Oracle-to-SQL-Server migrations look straightforward on paper — both are enterprise relational databases with decades of battle-tested features. In practice, the gap between PL/SQL and T-SQL, the divergent type systems, and Oracle-specific idioms buried deep in application code turn what looks like a lift-and-shift into a multi-month engineering project. Teams that skip the assessment phase almost always discover breaking incompatibilities days before cutover. This checklist distills the patterns that separate migrations that land cleanly from the ones that drag on for years.

TL;DR
  • Run a full pre-migration assessment before touching a single schema object — complexity scoring up front saves weeks downstream.
  • Map Oracle data types deliberately: NUMBERDECIMAL, DATEDATETIME2, VARCHAR2NVARCHAR.
  • Convert PL/SQL constructs systematically: ROWNUMTOP/ROW_NUMBER(), DECODECASE, sequences → IDENTITY/SEQUENCE.
  • Use Microsoft's free SSMA tool to automate schema and code conversion and generate an assessment report before writing a line of manual T-SQL.
  • Validate with row-count checks, checksum comparisons, and a functional regression suite — never rely on visual spot-checks alone.

Pre-Migration Assessment

The single biggest predictor of migration success is how thoroughly you understand what you are migrating before you start. Skipping this phase is how teams end up discovering Oracle-specific package dependencies at 2 AM the night before go-live.

Start by cataloging every schema object in the source database: tables, views, stored procedures, functions, packages, triggers, sequences, synonyms, database links, and scheduler jobs. Oracle's ALL_OBJECTS view gives you the full inventory.

sql
-- Inventory all schema objects by type
SELECT
    owner,
    object_type,
    COUNT(*) AS object_count,
    SUM(CASE WHEN status = 'INVALID' THEN 1 ELSE 0 END) AS invalid_count
FROM all_objects
WHERE owner NOT IN ('SYS','SYSTEM','DBSNMP','OUTLN','MDSYS','ORDSYS','EXFSYS','DMSYS','WMSYS','CTXSYS','ANONYMOUS','XDB','ORDPLUGINS','OLAPSYS','PUBLIC')
GROUP BY owner, object_type
ORDER BY owner, object_count DESC;

Next, score each object for migration complexity. A simple lookup table with no foreign keys and standard scalar columns is low risk. A PL/SQL package that wraps dynamic SQL, calls database links, uses DBMS_SCHEDULER, and references Oracle spatial types is a project of its own. Assign a weight to each object and sum the scores to get a migration complexity index for each schema. This number becomes your planning input for sprint sizing.

Document external dependencies explicitly: JDBC/OCI connection strings embedded in application configuration files, ETL pipelines that rely on Oracle change data capture, reporting tools with Oracle-dialect SQL baked into their metadata layer, and any application code that calls ORA_ROWSCN or other Oracle-proprietary pseudocolumns. Each dependency is a separate work item with its own acceptance criteria.

Important

Oracle DATE stores both date and time components with second precision. SQL Server's DATE type stores date only. If you map Oracle DATE columns to SQL Server DATE, you will silently truncate time data. Always map Oracle DATE to DATETIME2(0) or DATETIME2(6) depending on the required precision. Audit every Oracle DATE column to determine whether it is used as a pure date or a datetime before choosing the target type.

Data Type Mapping (Oracle → SQL Server)

Data type mismatches are the most common source of silent data corruption in database migrations. The table below covers the mappings you will encounter on the majority of OLTP schemas. Edge cases — Oracle INTERVAL types, XMLTYPE, spatial types, and RAW — require individual treatment.

Oracle Type SQL Server Type Notes
NUMBER(p, s) DECIMAL(p, s) Use DECIMAL for fixed precision. Unqualified NUMBER (no precision) maps to FLOAT only when the column stores scientific values; otherwise use DECIMAL(38, 10) as a safe default and tune per column.
NUMBER(p) where p ≤ 9 INT Prefer INT or BIGINT for integer-only columns to save storage and improve join performance.
DATE DATETIME2(0) Oracle DATE includes time; SQL Server DATE does not. Use DATETIME2 to preserve time components.
TIMESTAMP(p) DATETIME2(p) Direct mapping. Oracle supports up to 9 fractional second digits; SQL Server supports up to 7. Precision 7 is safe for most workloads.
TIMESTAMP WITH TIME ZONE DATETIMEOFFSET Preserves UTC offset. Validate application timezone handling after migration.
VARCHAR2(n) NVARCHAR(n) Use NVARCHAR (Unicode) unless you can guarantee all data is ASCII-only and storage savings are a priority, in which case VARCHAR is acceptable.
CHAR(n) NCHAR(n) Same Unicode rationale as VARCHAR2. Trailing-space comparison semantics differ between Oracle and SQL Server — audit queries that use CHAR columns in predicates.
CLOB NVARCHAR(MAX) SQL Server 2022 supports up to 2 GB in NVARCHAR(MAX). Confirm application drivers handle large-value types correctly.
BLOB VARBINARY(MAX) Consider FILESTREAM for very large binary objects if file-system access patterns are needed.
FLOAT(p) FLOAT(53) Oracle FLOAT precision is in bits; SQL Server FLOAT precision is also in bits. Oracle FLOAT(126) maps to SQL Server FLOAT(53) (double precision).
Tip

Run a column-level type audit query against ALL_TAB_COLUMNS before finalizing your mapping decisions. Aggregate the distinct DATA_TYPE, DATA_PRECISION, DATA_SCALE, and CHAR_LENGTH combinations across all target schemas. You will likely find that 80% of your columns fall into five or six type patterns — standardize those first and handle the long tail individually.

PL/SQL to T-SQL Conversion

Syntactic differences between PL/SQL and T-SQL are well-documented; semantic differences are where migrations break. The constructs below account for the majority of manual conversion work on typical OLTP schemas.

ROWNUM vs. TOP / ROW_NUMBER() — Oracle's ROWNUM pseudocolumn is assigned before ORDER BY is evaluated, which surprises developers who expect it to behave like SQL Server's TOP. For simple top-N queries, TOP is the correct replacement. For pagination, use ROW_NUMBER() OVER (ORDER BY ...).

sql
-- Oracle: first 10 rows by salary (unreliable ordering with ROWNUM)
SELECT * FROM employees WHERE ROWNUM <= 10 ORDER BY salary DESC;

-- SQL Server: correct equivalent using TOP with ORDER BY
SELECT TOP 10 * FROM employees ORDER BY salary DESC;

-- Oracle: pagination with ROWNUM (verbose and fragile)
SELECT * FROM (
  SELECT e.*, ROWNUM rn FROM (
    SELECT * FROM employees ORDER BY salary DESC
  ) e WHERE ROWNUM <= 20
) WHERE rn > 10;

-- SQL Server: clean pagination with ROW_NUMBER()
SELECT * FROM (
  SELECT *, ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn
  FROM employees
) ranked
WHERE rn BETWEEN 11 AND 20;

DECODE vs. CASE — Oracle's DECODE is a legacy equality-only switch expression. SQL Server's CASE is the ANSI standard and handles range predicates as well. The conversion is mechanical but must be done consistently across all stored procedures, views, and ad hoc query libraries.

sql
-- Oracle DECODE
SELECT DECODE(status, 'A', 'Active', 'I', 'Inactive', 'Unknown') FROM accounts;

-- SQL Server CASE equivalent
SELECT
  CASE status
    WHEN 'A' THEN 'Active'
    WHEN 'I' THEN 'Inactive'
    ELSE 'Unknown'
  END
FROM accounts;

Sequences and IDENTITY — Oracle sequences are standalone schema objects referenced via sequence_name.NEXTVAL. In SQL Server, use IDENTITY for simple auto-increment primary keys, or create a SEQUENCE object (available since SQL Server 2012) when you need cross-table sequence sharing or the ability to cache and pre-allocate values.

sql
-- Oracle sequence usage in INSERT
INSERT INTO orders (order_id, customer_id, order_date)
VALUES (order_seq.NEXTVAL, 101, SYSDATE);

-- SQL Server with IDENTITY column (DDL)
CREATE TABLE orders (
  order_id    INT IDENTITY(1,1) PRIMARY KEY,
  customer_id INT NOT NULL,
  order_date  DATETIME2(0) NOT NULL DEFAULT SYSDATETIME()
);

-- SQL Server with SEQUENCE object (equivalent to Oracle standalone sequence)
CREATE SEQUENCE dbo.order_seq
  START WITH 1
  INCREMENT BY 1
  CACHE 50;

INSERT INTO orders (order_id, customer_id, order_date)
VALUES (NEXT VALUE FOR dbo.order_seq, 101, SYSDATETIME());

Additional constructs requiring conversion include: NVLISNULL or COALESCE, SYSDATESYSDATETIME(), CONNECT BY hierarchical queries → recursive CTEs (WITH ... AS (... UNION ALL ...)), Oracle packages → SQL Server schemas with grouped stored procedures, and BULK COLLECT/FORALL patterns → set-based T-SQL with table variables or temporary tables.

Using SSMA (SQL Server Migration Assistant)

SSMA for Oracle is a free Microsoft tool that automates the mechanical portions of schema and code conversion. It connects directly to the Oracle source and SQL Server target, generates a conversion assessment report with a complexity score for each object, and produces converted T-SQL DDL and stored procedure code. SSMA does not replace human review — it generates a starting point, not a finished migration — but it eliminates several weeks of manual DDL rewriting on large schemas.

The SSMA workflow follows five phases. First, connect to the Oracle source and load the schema metadata. Second, run the assessment report to identify which objects will convert automatically, which will convert with warnings, and which SSMA cannot convert. Third, run the automatic conversion and review the output — SSMA inserts inline comments flagging every construct it could not convert cleanly. Fourth, manually fix the flagged objects. Fifth, synchronize the converted schema to the SQL Server target and migrate the data.

Tip

Pay close attention to SSMA's assessment report before starting conversion. The report groups objects by conversion category: "No issues", "Information messages", "Warnings", and "Errors". Objects in the "Errors" category require manual rewriting and should be tracked as individual work items. On a typical 500-procedure OLTP schema, expect roughly 15–25% of procedures to require manual intervention after SSMA conversion.

SSMA also handles data migration for moderate dataset sizes using its built-in data migration engine. For large tables (hundreds of millions of rows), use SQL Server Integration Services (SSIS) or a bulk copy approach with bcp or BULK INSERT instead — SSMA's data migration engine does not parallelize at the table-partition level and will bottleneck on very large volumes.

Validation and Cutover Strategy

Validation is not a phase that happens at the end — it runs in parallel with conversion from the moment the first table lands on the SQL Server target. Deferred validation amplifies the cost of every error.

Row count verification is the baseline check. Every table in the source must match the target row count exactly after the initial load and after any incremental sync passes.

sql
-- Row count comparison query (run on SQL Server side after migration)
-- Assumes a linked server or manual collection of Oracle counts into a staging table
SELECT
    src.table_name,
    src.oracle_row_count,
    tgt.mssql_row_count,
    src.oracle_row_count - tgt.mssql_row_count AS delta
FROM oracle_row_counts src
JOIN (
    SELECT t.name AS table_name, p.rows AS mssql_row_count
    FROM sys.tables t
    JOIN sys.partitions p ON t.object_id = p.object_id AND p.index_id IN (0,1)
) tgt ON UPPER(src.table_name) = UPPER(tgt.table_name)
WHERE src.oracle_row_count <> tgt.mssql_row_count
ORDER BY ABS(src.oracle_row_count - tgt.mssql_row_count) DESC;

Checksum comparison goes one level deeper than row counts by detecting corrupted or mismatched column values. Compute an aggregate checksum over key business columns on both sides and compare the results. Oracle's ORA_HASH and SQL Server's CHECKSUM_AGG use different algorithms, so the comparison must be done by extracting matching column values and hashing them on a common platform, or by using a purpose-built data comparison tool such as Red Gate SQL Data Compare or Attunity Replicate's validation module.

Functional regression testing is the highest-fidelity validation layer. Capture a representative set of application queries against the Oracle source — including stored procedure calls with realistic parameter sets — record their result sets, then replay the same calls against the SQL Server target and diff the outputs. Automate this with a test harness that runs nightly against the migrated environment throughout the conversion project, not just at cutover.

For the cutover itself, plan for a brief maintenance window even in migrations that use continuous replication for data sync. The window covers: stopping writes to Oracle, applying the final incremental data sync, validating the delta, updating application connection strings, and flipping DNS or load-balancer targets. Practice the cutover procedure at least twice in a staging environment to get an accurate window estimate before scheduling production.

Important

Keep the Oracle source online and read-accessible for at least 30 days after cutover. Operational teams will encounter edge-case queries, historical reports, and audit requests that surface weeks after go-live. Having the Oracle source available as a read-only reference eliminates the pressure to roll back the migration for minor discrepancies that can be resolved without touching the new SQL Server environment.

Key Takeaways
  • A structured pre-migration assessment with object-level complexity scoring is not optional — it is the foundation every subsequent estimate is built on.
  • Map Oracle DATE to DATETIME2, NUMBER to DECIMAL, and VARCHAR2 to NVARCHAR as your baseline type mapping; audit every deviation from this baseline individually.
  • Convert ROWNUM to TOP or ROW_NUMBER() OVER (...), DECODE to CASE, and Oracle sequences to IDENTITY or SQL Server SEQUENCE objects.
  • Run SSMA early to generate the assessment report and automated conversion output; plan for 15–25% of procedures to require manual T-SQL rewriting.
  • Validate with row-count checks, checksum comparisons, and an automated functional regression suite running throughout the project — not just at cutover.
  • Practice the cutover window at least twice in staging before scheduling production, and keep Oracle online in read-only mode for 30 days post-migration.

Working with JusDB on SQL Server Migration

JusDB's database engineering team has executed Oracle-to-SQL-Server migrations across OLTP systems, data warehouses, and mixed-workload environments. Our migration engagements begin with a structured assessment that produces an object inventory, complexity index, and phased project plan before any conversion work starts. We use SSMA as the baseline automation layer, pair it with manual T-SQL conversion for complex PL/SQL packages, and run continuous validation throughout the engagement — not as a gate at the end. If you are evaluating a migration or have already started one that has stalled, we can step in at any phase.

Explore JusDB SQL Server Migration Services →  |  Talk to a DBA

Need hands-on SQL Server help?

JusDB's certified SQL Server DBAs handle performance tuning, Always On AG, migrations, and 24/7 operations.

SQL Server Consulting →  |  SQL Server Remote DBA →  |  24/7 SQL Server Support →

Share this article

Keep reading

PostgreSQL 19 Beta: Every New Feature That Matters to DBAs

PostgreSQL 19 Beta 1 (June 4, 2026) brings parallel autovacuum, the native REPACK command for online table rebuilds, 2x faster inserts under foreign-key load, online logical replication without a restart, WAIT FOR LSN for read-your-writes consistency, and default changes (JIT off, lz4 TOAST, RADIUS removed). A DBA-focused walkthrough of what changed and what to test before GA.

PostgreSQL14 minJun 15, 2026
Read

High Performance with MongoDB: A Top-Down Tuning Guide

A top-down playbook for high-performance MongoDB: measure with the profiler and explain(), model for access patterns, index by the ESR rule, keep the working set in the WiredTiger cache, pool connections, and scale reads with secondaries and sharding — with flow diagrams for each layer.

MongoDB14 minJun 6, 2026
Read

Migrate On-Premises SQL Server to Amazon RDS: Native Backup/Restore vs AWS DMS

A step-by-step guide to migrating an on-premises Microsoft SQL Server database to Amazon RDS for SQL Server — covering native backup/restore via S3 with the rds_restore_database stored procedure, AWS DMS full-load + CDC for near-zero downtime, option group and IAM setup, cutover, and post-migration hardening.

AWS15 minJun 2, 2026
Read