1. Home
  2. Docs
  3. Oracle to PostgreSQL Migration
  4. Database Migration Basics
  5. Oracle to PostgreSQL Complete Reference

Oracle to PostgreSQL Complete Reference

Each database is different from another in many ways. During migration from Oracle to PostgreSQL, you must first know what Oracle database objects and features are supported in PostgreSQL and to what extent features need special handling in PostgreSQL.

This article covers the equivalent PostgreSQL database constructs for Oracle SQL and PL/SQL language elements and will help you in doing code migration. The link provided for each section describes the differences and the proper way to handle in PostgreSQL.

Schema objects when migrating from Oracle to PostgreSQL

ORACLEPOSTGRESQL
Constraint (Primary Key, Foreign Key, Unique Key, CHECK, NOT NULL, REF)Constraints are supported but has differences. PostgreSQL does not support Oracle’s REF constraint.

See Details
IndexIndexes are supported but has differences. Domain index is not supported in PostgreSQL.

See Details
VIEWViews are supported in PostgreSQL, but some Oracle’s view features are not supported such as FORCE, WITH READ ONLY.

See Details
Materialized ViewMaterialized View exists but refresh mechanisms are different.

See Details
SequenceThere is difference between the syntax of sequence in Oracle and PostgreSQL.

–Oracle
Sequence_name.nextval

–PostgreSQL
nextval(‘sequence_name’)
SynonymSynonym is not supported in PostgreSQL. Use SET search_path to access objects in other schemas.

See Details
TYPEConverted to TYPE or DOMAIN in PostgreSQL.

See Details
Collections – Associative Array, Nested Table, VarrayCollections are not available in PostgreSQL. PostgreSQL provides arrays which are alternate solution for Oracle collections.

See Details
Stored FunctionFunctions available in PostgreSQL which are operationally more flexible compared to Oracle functions.

See Details
Stored ProcedureProcedures are available in PostgreSQL 11 onwards and has lot of limitations in PostgreSQL. They are used only for specific purpose.

See Details
PackagePackages in Oracle provide a mechanism to encapsulate related procedures, functions, and other program units. PostgreSQL does not have package but has schemas which can be leveraged to group related objects. Accessing objects also remain same and no application changes required.

–Oracle
package_name.object_name

–PostgreSQL
schema_name.object_name
TriggerUnlike Oracle, triggers in PostgreSQL don’t provide trigger code directly, but call a trigger function, which can be called from any number of triggers, though often they are customized for one particular event on one particular table.

See Details

Oracle Commands when migrating to PostgreSQL

ORACLEPostgreSQL
FROM clause is mandatory in any SELECT statement. Oracle database provides “DUAL” table (A single row single column table) if working with literals or expressions.

Example 1:
SELECT 'ABC' res FROM DUAL;

Example 2:
SELECT sysdate res FROM DUAL;
FROM clause is not mandatory in PostgreSQL, DUAL can be removed. You can create a table or a view to ease code porting problems.

Example 1:
SELECT 'ABC' res;

Example 2:
SELECT current_date res;
In Oracle, DELETE statement can work without FROM clause.

DELETE <table_name> WHERE <column_name> = 'value';
Add FROM clause in PostgreSQL DELETE statement manually.

DELETE FROM <table_name> WHERE <column_name> = 'value';

Built-in functions and operators when migrating from Oracle to PostgreSQL

ORACLEPostgreSQL
NULL or Empty String (Both are same in Oracle database)

IS NULL/ IS NOT NULL
NULL and Empty String both are treated differently in PostgreSQL. Oracle treats empty strings as NULL whereas this behavior differs in PostgreSQL and needs to be taken care.

See Details
NVLNVL function does not exist in PostgreSQL, use COALESCE function instead. Make sure to use NULLIF function within coalesce to handle empty strings.
Example- COALESCE(nullif($1, ''), $2) where $1 and $2 are arguments to coalesce.
Pipe operator || (String concatenation operator)PostgreSQL supports pipe “||” operator for string concatenation but the behavior differs from Oracle with respect to NULL.

See Details
SYSDATEOracle’s SYSDATE function returns date and time. No SYSDATE function is available in PostgreSQL, but there are multiple methods to get the date and time and it is dependent on the application purpose.

CURRENT_DATE – Provides only the date. Use if not concerned about time factor.
NOW() / CURRENT_TIMESTAMP() – If time factor is required, but has to be same through out the transaction. Same for each statement within a transaction.
CLOCK_TIMESTAMP()When time factor is required and has to record the exact statement execution time within a transaction. Different for each statement within a transaction.
INSTRPostgreSQL database does not have INSTR function, but has STRPOS function which works in a similar way, but has some differences.

See Details
DECODEPostgreSQL database does not have DECODE or a similar function, but you can convert DECODE to CASE expression.

See Details
SUBSTRSUBSTR function exists in PostgreSQL but has differences when the 2nd parameter is negative. In this case the SUBSTR function works without error but returns a different result.

1. Use Orafce SUBSTR function which returns the same result as Oracle in PostgreSQL.
2. Use AWS SCT extension function for SUBSTR.

Oracle features when migrating to PostgreSQL

ORACLEPostgreSQL
MERGEPostgreSQL doesn’t have a direct MERGE-like construct. However, in PostgreSQL 9.5, the ON CONFLICT clause was added to INSERT, which is the recommended option for many of the Oracle MERGE statements conversion in PostgreSQL.

See Details
JOINExcept Oracle native outer joins, most of the Join types works same in PostgreSQL as well and might not require code change during conversion.

See Details
SUBQUERY

SELECT * FROM (SELECT * FROM table_a);
PostgreSQL requires inline SELECT (subquery in FROM clause) surrounded by parentheses must be provided an alias. The alias is not mandatory for Oracle.

SELECT * FROM (SELECT * FROM table_a) AS foo;

See Details
Hierarchical queries like CONNECT BY, START WITH, LEVEL etc.PostgreSQL does not have hierarchical CONNECT BY queries. PostgreSQL provides WITH RECURSIVE clause which is an alternate option for hierarchical queries. All of Oracle CONNECT BY, START WITH queries can be converted to PostgreSQL equivalent using WITH RECURSIVE clause.

See Details
ROWNUM

SELECT ROWNUM rn, empno, ename, sal
FROM Emp
WHERE Job = 'MANAGER';
Oracle’s pseudocolumn ROWNUM returns a number which is assigned at the moment when data is read, but before the ORDER BY is executed.
There is no direct ROWNUM like feature available in PostgreSQL. You might consider to replace ROWNUM by using ROW_NUMBER() OVER () which will work in many cases.

SELECT row_number() over() rn, empno, ename, sal
FROM Emp
WHERE Job = 'MANAGER';


Note: The order of rows may not be same in Oracle and PostgreSQL. If you wish to have same rows, you need to specify explicit ORDER BY clause in a subquery.
ROWID

Oracle’s pseudocolumn ROWID returns the physical address of a table row, encoded in base64. In PL/SQL programs they are used to temporarily cache the address of rows to locate them easier a second time. Postgres has ctid which serves the same purpose.
Anonymous BlockSyntax change.

See Details
SYS_REFCURSORREFCURSOR
CURSORCursor feature is available in PostgreSQL, but need to be handled correctly while migrating to PostgreSQL.

See Details
NEW_TIME – PL/SQL NEW_TIME function converts a date and time from one timezone to a date in another timezone.PostgreSQL does not have any similar function like NEW_TIME. Create wrapper function.

See Details
DBMS_OUTPUT.PUT_LINERAISE statement in PostgreSQL is used to display messages, debugging and raise errors.

See Details
BULK COLLECTNo such equivalent syntax in PostgreSQL. But you can leverage array_agg function available in PostgreSQL.

See Details
NO_DATA_FOUND and TOO_MANY_ROWSBy default SELECT statements in PLpgSQL do not throw these exceptions. You need to add keyword STRICT after any keyword INTO in all selects, when you need to keep single row checking in stored PLpgSQL code.

Was this article helpful to you? Yes No

How can we help?