Skip to content

Oracle to Azure -- Complete Feature Mapping

50+ Oracle Database features mapped to Azure SQL Managed Instance, Azure Database for PostgreSQL, and Oracle Database@Azure equivalents with migration complexity ratings.


How to read this guide

Each feature is rated for migration complexity: XS (trivial, syntax change only), S (small, documented pattern), M (medium, requires refactoring), L (large, significant redesign), XL (very large, architectural change). The "CSA-in-a-Box integration" column shows how the feature connects to the analytics platform.


1. Core SQL and data types

1.1 Data types

Oracle data type Azure SQL MI equivalent PostgreSQL equivalent Conversion notes Complexity
NUMBER(p,s) decimal(p,s) / int / bigint numeric(p,s) / integer / bigint SSMA auto-maps; choose integer types for whole numbers for performance XS
NUMBER (no precision) float(53) double precision Beware: Oracle NUMBER without precision is arbitrary precision; float(53) is IEEE 754 S
VARCHAR2(n) nvarchar(n) varchar(n) Azure SQL uses Unicode by default (nvarchar); PostgreSQL varchar is already Unicode XS
NVARCHAR2(n) nvarchar(n) varchar(n) Direct mapping; PostgreSQL varchar handles Unicode natively XS
CHAR(n) nchar(n) char(n) Watch for trailing space comparison semantics differences XS
DATE datetime2(0) timestamp(0) Oracle DATE includes time component; SQL Server DATE does not -- use datetime2 S
TIMESTAMP datetime2(7) timestamp(6) Precision difference: SQL Server max 7 fractional digits, PostgreSQL max 6 XS
TIMESTAMP WITH TIME ZONE datetimeoffset timestamptz Direct mapping XS
TIMESTAMP WITH LOCAL TIME ZONE datetime2 + application logic timestamptz No direct SQL Server equivalent; PostgreSQL timestamptz is close S
CLOB nvarchar(max) text Direct mapping; max 2 GB in all targets XS
BLOB varbinary(max) bytea Direct mapping XS
BFILE varbinary(max) + external reference bytea + external reference No direct equivalent; store file content or keep reference to Azure Blob M
RAW(n) varbinary(n) bytea Direct mapping XS
LONG nvarchar(max) text Deprecated in Oracle; migrate to CLOB/nvarchar(max) S
LONG RAW varbinary(max) bytea Deprecated in Oracle; migrate to BLOB/varbinary(max) S
XMLTYPE xml xml Direct mapping; XQuery syntax differs slightly S
SDO_GEOMETRY geometry / geography geometry (PostGIS) Requires PostGIS extension for PostgreSQL; SQL Server has built-in spatial M
ROWID / UROWID No equivalent ctid (not stable) Physical row identifier; do not migrate -- use logical keys instead M
INTERVAL YEAR TO MONTH Compute with DATEDIFF interval PostgreSQL has native interval type; SQL Server requires calculation S
INTERVAL DAY TO SECOND Compute with DATEDIFF interval PostgreSQL has native interval type S
BOOLEAN (PL/SQL only) bit boolean Oracle SQL does not have BOOLEAN; PL/SQL does. Both targets support it XS
JSON (Oracle 21c+) nvarchar(max) with JSON functions jsonb PostgreSQL jsonb is more capable; SQL Server JSON is string-based S

1.2 SQL syntax differences

Oracle SQL feature Azure SQL MI equivalent PostgreSQL equivalent Complexity
SELECT ... FROM DUAL SELECT ... (no FROM needed) SELECT ... (no FROM needed) XS
ROWNUM ROW_NUMBER() OVER (ORDER BY ...) or TOP ROW_NUMBER() OVER (ORDER BY ...) or LIMIT S
CONNECT BY / START WITH Recursive CTE (WITH RECURSIVE) Recursive CTE (WITH RECURSIVE) M
DECODE(expr, val1, res1, ...) CASE expr WHEN val1 THEN res1 ... or IIF CASE expr WHEN val1 THEN res1 ... XS
NVL(expr, default) ISNULL(expr, default) or COALESCE COALESCE(expr, default) XS
NVL2(expr, not_null, null_val) CASE WHEN expr IS NOT NULL THEN ... ELSE ... CASE WHEN expr IS NOT NULL THEN ... ELSE ... XS
LISTAGG(col, ',') STRING_AGG(col, ',') string_agg(col, ',') XS
(+) outer join syntax LEFT/RIGHT JOIN ... ON LEFT/RIGHT JOIN ... ON S
MERGE INTO MERGE INTO (same syntax) INSERT ... ON CONFLICT S
SEQUENCE.NEXTVAL NEXT VALUE FOR sequence nextval('sequence') XS
SYSDATE GETDATE() or SYSDATETIME() now() or current_timestamp XS
SYSTIMESTAMP SYSDATETIMEOFFSET() clock_timestamp() XS
TO_DATE('...', 'format') CONVERT(datetime2, '...', style) or TRY_PARSE to_timestamp('...', 'format') S
TO_CHAR(date, 'format') FORMAT(date, 'format') to_char(date, 'format') S
TO_NUMBER('...') CAST('...' AS decimal) or TRY_CAST '...'::numeric or to_number XS
SUBSTR(str, start, len) SUBSTRING(str, start, len) substr(str, start, len) XS
INSTR(str, substr) CHARINDEX(substr, str) position(substr in str) or strpos XS
LENGTH(str) LEN(str) length(str) XS
TRUNC(date) CAST(date AS date) date_trunc('day', date) XS
ADD_MONTHS(date, n) DATEADD(month, n, date) date + interval 'n months' XS
MONTHS_BETWEEN(d1, d2) DATEDIFF(month, d2, d1) EXTRACT(EPOCH FROM age(d1, d2))/2629746 S

2. PL/SQL to T-SQL and PL/pgSQL

2.1 Procedural language constructs

Oracle PL/SQL Azure SQL T-SQL PostgreSQL PL/pgSQL Complexity
CREATE OR REPLACE PROCEDURE CREATE OR ALTER PROCEDURE CREATE OR REPLACE PROCEDURE XS
CREATE OR REPLACE FUNCTION CREATE OR ALTER FUNCTION CREATE OR REPLACE FUNCTION XS
CREATE OR REPLACE PACKAGE Schema + individual procedures/functions Schema + individual procedures/functions M
PACKAGE BODY No equivalent (use schema grouping) No equivalent (use schema grouping) M
%TYPE Declare with explicit type Use %TYPE (supported in PL/pgSQL) S
%ROWTYPE Table variable or temp table Use %ROWTYPE (supported in PL/pgSQL) S
CURSOR FOR LOOP DECLARE CURSOR + FETCH + WHILE FOR record IN query LOOP S
BULK COLLECT + FORALL Set-based operations (preferred) ARRAY + set-based operations M
EXCEPTION WHEN TRY...CATCH EXCEPTION WHEN S
RAISE_APPLICATION_ERROR THROW or RAISERROR RAISE EXCEPTION XS
DBMS_OUTPUT.PUT_LINE PRINT RAISE NOTICE XS
AUTONOMOUS_TRANSACTION Loopback linked server or separate connection dblink extension L
EXECUTE IMMEDIATE sp_executesql or EXEC EXECUTE S
REF CURSOR Output parameter with result set REFCURSOR S
SYS_REFCURSOR Result set from stored procedure REFCURSOR S
PIPELINED FUNCTION Table-valued function RETURNS TABLE function M
PRAGMA RESTRICT_REFERENCES Not needed Not needed XS
DETERMINISTIC WITH SCHEMABINDING (for indexed views) IMMUTABLE / STABLE XS
RESULT_CACHE Query Store + plan cache pg_prewarm + shared_buffers M

2.2 PL/SQL package conversion example

Oracle PL/SQL package:

-- Oracle PL/SQL
CREATE OR REPLACE PACKAGE emp_pkg AS
    FUNCTION get_salary(p_emp_id NUMBER) RETURN NUMBER;
    PROCEDURE update_salary(p_emp_id NUMBER, p_new_salary NUMBER);
    PROCEDURE transfer_employee(p_emp_id NUMBER, p_new_dept NUMBER);
END emp_pkg;
/

CREATE OR REPLACE PACKAGE BODY emp_pkg AS
    FUNCTION get_salary(p_emp_id NUMBER) RETURN NUMBER IS
        v_salary NUMBER;
    BEGIN
        SELECT salary INTO v_salary FROM employees WHERE employee_id = p_emp_id;
        RETURN v_salary;
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            RETURN NULL;
    END get_salary;

    PROCEDURE update_salary(p_emp_id NUMBER, p_new_salary NUMBER) IS
    BEGIN
        UPDATE employees SET salary = p_new_salary WHERE employee_id = p_emp_id;
        IF SQL%ROWCOUNT = 0 THEN
            RAISE_APPLICATION_ERROR(-20001, 'Employee not found');
        END IF;
    END update_salary;

    PROCEDURE transfer_employee(p_emp_id NUMBER, p_new_dept NUMBER) IS
    BEGIN
        UPDATE employees SET department_id = p_new_dept WHERE employee_id = p_emp_id;
        INSERT INTO transfer_log (employee_id, new_department_id, transfer_date)
        VALUES (p_emp_id, p_new_dept, SYSDATE);
    END transfer_employee;
END emp_pkg;
/

Converted to T-SQL (Azure SQL MI):

-- T-SQL (Azure SQL MI)
-- Package becomes a schema
CREATE SCHEMA emp_pkg;
GO

CREATE OR ALTER FUNCTION emp_pkg.get_salary(@emp_id int)
RETURNS decimal(10,2)
AS
BEGIN
    DECLARE @salary decimal(10,2);
    SELECT @salary = salary FROM dbo.employees WHERE employee_id = @emp_id;
    RETURN @salary;  -- Returns NULL if not found (no exception needed)
END;
GO

CREATE OR ALTER PROCEDURE emp_pkg.update_salary
    @emp_id int,
    @new_salary decimal(10,2)
AS
BEGIN
    SET NOCOUNT ON;
    UPDATE dbo.employees SET salary = @new_salary WHERE employee_id = @emp_id;
    IF @@ROWCOUNT = 0
        THROW 50001, 'Employee not found', 1;
END;
GO

CREATE OR ALTER PROCEDURE emp_pkg.transfer_employee
    @emp_id int,
    @new_dept int
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRANSACTION;
    BEGIN TRY
        UPDATE dbo.employees SET department_id = @new_dept WHERE employee_id = @emp_id;
        INSERT INTO dbo.transfer_log (employee_id, new_department_id, transfer_date)
        VALUES (@emp_id, @new_dept, GETDATE());
        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION;
        THROW;
    END CATCH;
END;
GO

Converted to PL/pgSQL (Azure PostgreSQL):

-- PL/pgSQL (Azure Database for PostgreSQL)
-- Package becomes a schema
CREATE SCHEMA IF NOT EXISTS emp_pkg;

CREATE OR REPLACE FUNCTION emp_pkg.get_salary(p_emp_id integer)
RETURNS numeric AS $$
DECLARE
    v_salary numeric;
BEGIN
    SELECT salary INTO v_salary FROM employees WHERE employee_id = p_emp_id;
    RETURN v_salary;  -- Returns NULL if not found
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        RETURN NULL;
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE PROCEDURE emp_pkg.update_salary(
    p_emp_id integer,
    p_new_salary numeric
) AS $$
BEGIN
    UPDATE employees SET salary = p_new_salary WHERE employee_id = p_emp_id;
    IF NOT FOUND THEN
        RAISE EXCEPTION 'Employee not found' USING ERRCODE = 'P0001';
    END IF;
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE PROCEDURE emp_pkg.transfer_employee(
    p_emp_id integer,
    p_new_dept integer
) AS $$
BEGIN
    UPDATE employees SET department_id = p_new_dept WHERE employee_id = p_emp_id;
    INSERT INTO transfer_log (employee_id, new_department_id, transfer_date)
    VALUES (p_emp_id, p_new_dept, now());
END;
$$ LANGUAGE plpgsql;

3. High availability and disaster recovery

Oracle feature Azure SQL MI Azure PostgreSQL Oracle DB@Azure Complexity
Real Application Clusters (RAC) Failover groups (active-passive with auto-failover) Zone-redundant HA (synchronous standby) RAC (native) L
Active Data Guard Geo-replication (readable secondary in different region) Read replicas (up to 5 per region) Active Data Guard (native) M
Data Guard (physical standby) Auto-failover groups Zone-redundant HA Data Guard (native) M
Data Guard Broker Azure Portal / CLI (automated) Azure Portal / CLI (automated) Data Guard Broker (native) S
Fast-Start Failover Auto-failover groups (< 30s failover) Automatic failover (< 60s) Fast-Start Failover (native) S
Maximum Availability Architecture (MAA) Business Critical tier + geo-replication Zone-redundant + read replicas MAA (native) M
Flashback Database Point-in-time restore (up to 35 days) Point-in-time recovery (up to 35 days) Flashback (native) S
Flashback Table Temporal tables No direct equivalent (use PITR) Flashback (native) M
Online Redefinition Online index operations, ALTER TABLE ... ONLINE ALTER TABLE (most operations online) Online Redefinition (native) S

RAC vs. failover groups

Oracle RAC provides active-active multi-node clustering where all nodes serve read-write workloads simultaneously. Azure SQL MI failover groups are active-passive with automatic failover. For workloads that genuinely require active-active (rare in practice -- most RAC deployments use one node for reads and one for writes), Oracle Database@Azure retains RAC capability. For the majority of OLTP workloads, active-passive with automatic failover provides equivalent application availability.


4. Partitioning

Oracle feature Azure SQL MI Azure PostgreSQL Complexity
Range partitioning Partition schemes + partition functions Declarative partitioning (PARTITION BY RANGE) M
List partitioning Partition schemes + partition functions Declarative partitioning (PARTITION BY LIST) M
Hash partitioning Partition schemes + partition functions Declarative partitioning (PARTITION BY HASH) M
Composite partitioning Sub-partitioning with partition schemes Sub-partitioning (PostgreSQL 13+) M
Interval partitioning Manual + SQL Agent job for auto-create pg_partman extension for auto-create M
Virtual column partitioning Computed columns + partition schemes Generated columns + partitioning M
Partition exchange ALTER TABLE ... SWITCH PARTITION ALTER TABLE ... ATTACH/DETACH PARTITION S
Partition pruning Automatic (query optimizer) Automatic (query optimizer) XS
Global indexes on partitioned tables Aligned indexes (auto-maintained) Global indexes not supported (use local) M

5. Materialized views

Oracle feature Azure SQL MI Azure PostgreSQL Complexity
Materialized view (basic) Indexed views (CREATE VIEW ... WITH SCHEMABINDING) CREATE MATERIALIZED VIEW M
Complete refresh Drop + recreate indexed view, or manual table REFRESH MATERIALIZED VIEW S
Fast refresh (incremental) Indexed views auto-refresh on DML REFRESH MATERIALIZED VIEW CONCURRENTLY (but not incremental -- full refresh) M
Materialized view log No equivalent (indexed views are always current) No equivalent (consider logical replication triggers) L
Query rewrite Automatic for indexed views Not automatic (application must reference MV) M
On-demand refresh N/A (indexed views are synchronous) REFRESH MATERIALIZED VIEW on schedule S

CSA-in-a-Box alternative

For analytics workloads, consider replacing Oracle materialized views with Fabric Mirroring + dbt models. dbt incremental models in CSA-in-a-Box provide materialization with lineage tracking, testing, and documentation -- a more capable alternative than database-level materialized views for analytics use cases.


6. Scheduling and automation

Oracle feature Azure SQL MI Azure PostgreSQL Complexity
DBMS_SCHEDULER SQL Server Agent jobs pg_cron extension M
DBMS_JOB (deprecated) SQL Server Agent jobs pg_cron extension M
Chains (multi-step jobs) SQL Agent job steps + sp_start_job pg_cron + shell scripts or ADF orchestration M
Event-based scheduling Event notifications + Service Broker LISTEN/NOTIFY + application logic M
External job execution SQL Agent + xp_cmdshell (restricted) or Azure Functions pg_cron + Azure Functions M
Lightweight jobs In-database automation pg_cron for simple schedules S

CSA-in-a-Box alternative

For cross-database orchestration, use Azure Data Factory pipelines (domains/shared/pipelines/adf/) instead of database-level schedulers. ADF provides visual orchestration, dependency management, retry logic, and monitoring across all Azure data services.


Oracle feature Azure SQL MI Azure PostgreSQL Complexity
Oracle Text (CONTEXT index) Full-Text Search (FTS) with CONTAINS tsvector + tsquery with GIN index M
CTXCAT index Full-Text Search with catalog tsvector with weighted ranking M
CTXRULE index No equivalent (use application logic) No equivalent L
CONTAINS query CONTAINS(col, 'term') col @@ to_tsquery('term') S
NEAR operator CONTAINS(col, 'NEAR((term1, term2), distance)') phraseto_tsquery or tsquery with positional M
Thesaurus Thesaurus file for FTS ts_rewrite or synonym dictionaries M
AUTO_FILTER (binary documents) IFilter for binary documents tika or external parser L

8. Messaging and queuing

Oracle feature Azure SQL MI Azure PostgreSQL Complexity
Advanced Queuing (AQ) Service Broker (in-database) or Azure Service Bus LISTEN/NOTIFY + Azure Service Bus L
AQ with JMS Azure Service Bus (JMS-compatible) Azure Service Bus (JMS-compatible) M
AQ multi-consumer Service Bus topics/subscriptions Service Bus topics/subscriptions M
AQ transactional enqueue/dequeue Service Broker (transactional) LISTEN/NOTIFY (non-transactional) or Service Bus L
Streams (deprecated) Change Data Capture (CDC) Logical replication M
Change Data Capture SQL Server CDC Logical decoding + wal2json M

Advanced Queuing migration

Oracle AQ with complex routing, multi-consumer topics, and transactional semantics is one of the most challenging Oracle features to migrate. Azure Service Bus is the recommended replacement for enterprise messaging. In-database alternatives (Service Broker, LISTEN/NOTIFY) work for simple patterns but do not match AQ's full capability. Plan additional effort for AQ-heavy applications.


9. Security features

Oracle feature Azure SQL MI Azure PostgreSQL Complexity
Transparent Data Encryption (TDE) TDE (included, no extra cost) Storage encryption (AES-256, included) XS
TDE with customer-managed keys TDE with Azure Key Vault Customer-managed keys with Key Vault S
Virtual Private Database (VPD) Row-Level Security (RLS) Row-Level Security (RLS) M
Oracle Label Security (OLS) RLS with classification column RLS with classification column L
Data Redaction Dynamic Data Masking anon extension or application-level M
Database Vault Azure RBAC + no sa access on MI pg_hba.conf + role separation M
Fine-Grained Auditing (FGA) SQL Server Audit + Azure Monitor pgAudit extension + Azure Monitor M
Unified Auditing Azure SQL Auditing (to blob/Log Analytics) pgAudit + Log Analytics M
Network Encryption (sqlnet.ora) TLS 1.2+ enforced by default TLS 1.2+ enforced by default XS
Wallet / External Password Store Azure Key Vault + managed identity Azure Key Vault + managed identity S
Kerberos authentication Entra ID (Kerberos-compatible) Entra ID / SCRAM-SHA-256 M
Proxy authentication Entra ID managed identity Entra ID managed identity M

See Security Migration for detailed conversion patterns.


10. Spatial features

Oracle feature Azure SQL MI Azure PostgreSQL Complexity
SDO_GEOMETRY geometry / geography types PostGIS geometry / geography M
Spatial indexes (R-tree) Spatial index GiST index on geometry column S
SDO_RELATE .STIntersects(), .STContains(), etc. ST_Intersects(), ST_Contains(), etc. S
SDO_WITHIN_DISTANCE .STDistance() < threshold ST_DWithin(geom, geom, distance) S
SDO_NN (nearest neighbor) .STDistance() with TOP <-> KNN operator with ORDER BY S
SDO_UTIL.TO_GEOJSON .STAsGeoJSON() (SQL Server 2016+) ST_AsGeoJSON() XS
Coordinate system transformations Limited built-in ST_Transform() (comprehensive SRID support) M
Linear referencing Limited ST_LineLocatePoint(), ST_LineSubstring() M
Network data model Not built-in pgRouting extension L
Raster data Not built-in PostGIS Raster L

PostGIS advantage

For spatial-heavy workloads (GIS, geospatial analytics, mapping), Azure Database for PostgreSQL with PostGIS provides more comprehensive spatial functionality than Azure SQL MI. PostGIS supports 300+ spatial functions, raster data, topology, 3D geometry, and coordinate system transformations. CSA-in-a-Box integrates spatial data through the GeoAnalytics tutorial (tutorials/03-geoanalytics-oss/).


11. Advanced features

Oracle feature Azure SQL MI Azure PostgreSQL Complexity
In-Memory Column Store In-Memory OLTP (Business Critical tier) Columnar extensions (citus_columnar) M
Result Cache Query Store + plan cache pg_prewarm + shared_buffers tuning M
Parallel Query Automatic parallelism (query optimizer) max_parallel_workers_per_gather S
Parallel DML Automatic for bulk operations Limited parallel DML M
Edition-Based Redefinition Blue-green deployment pattern Blue-green deployment pattern L
Multitenant (CDB/PDB) Managed instance per database Server per database or schema isolation M
JSON support (21c+) JSON_VALUE, JSON_QUERY, OPENJSON jsonb operators, jsonpath S
Graph (SQL Property Graph) Graph tables (SQL Server 2017+) Apache AGE extension L
Blockchain tables (21c+) Ledger tables (SQL Server 2022) No equivalent M
Machine Learning (Oracle ML) SQL Server ML Services (R/Python) pgml extension or Azure ML M
Application Continuity Connection retry logic + failover groups Connection pooling + retry logic M
Sharding Elastic database tools Citus distributed tables L

12. Triggers and constraints

Oracle feature Azure SQL MI Azure PostgreSQL Complexity
BEFORE triggers INSTEAD OF triggers on views, or convert to AFTER BEFORE triggers (native support) S
AFTER triggers AFTER triggers AFTER triggers XS
INSTEAD OF triggers INSTEAD OF triggers on views INSTEAD OF triggers on views XS
Statement-level triggers Statement-level triggers (default) Statement-level triggers XS
Row-level triggers Row-level triggers (using INSERTED/DELETED) Row-level triggers (FOR EACH ROW) S
Compound triggers Multiple separate triggers Multiple separate triggers M
Mutating table workaround Not needed (SQL Server handles differently) Not needed (PostgreSQL handles differently) S
System triggers (DDL) DDL triggers, event notifications Event triggers (DDL_COMMAND_END) M
CHECK constraints CHECK constraints CHECK constraints XS
DEFAULT values DEFAULT clause DEFAULT clause XS

13. Backup and recovery

Oracle feature Azure SQL MI Azure PostgreSQL Complexity
RMAN backup Automated (Azure-managed) Automated (Azure-managed) XS
RMAN incremental backup Automated differential backups Automated (WAL-based continuous) XS
Point-in-time recovery Up to 35-day retention Up to 35-day retention XS
Tablespace-level recovery Database-level restore Database-level restore S
Data Pump (expdp/impdp) BACPAC export/import or BCP pg_dump / pg_restore S
Flashback Database Point-in-time restore Point-in-time recovery S
Cross-region backup Geo-redundant backup storage Geo-redundant backup storage XS

14. Migration tooling summary

Tool Source Target What it does
SSMA for Oracle Oracle Database Azure SQL MI / SQL Server Schema assessment, conversion, data migration
ora2pg Oracle Database PostgreSQL Schema assessment, conversion, data migration
Azure Database Migration Service (DMS) Oracle Database Azure SQL MI / PostgreSQL Online and offline data migration
Azure Data Factory Oracle Database Any Azure target Batch data movement, orchestration
Oracle Data Pump + AzCopy Oracle Database Azure Blob + target import Bulk export/import for large datasets
Oracle GoldenGate Oracle Database Oracle DB@Azure / other targets Real-time replication, CDC
Oracle Zero Downtime Migration (ZDM) Oracle Database Oracle DB@Azure Automated Oracle-to-Oracle migration
Fabric Mirroring Azure SQL MI / Oracle DB@Azure OneLake Near-real-time replication for analytics

Maintainers: csa-inabox core team Last updated: 2026-04-30