1. Home
  2. Docs
  3. Oracle to PostgreSQL Migration
  4. Built-in Functions
  5. decode

decode

DECODE function in Oracle is an extension to CASE expression and have the following syntax.

DECODE(expr, val1, res1, val2, res2, .., default)

DECODE compares expr to each search value val1, val2 one by one and goes on.

  • If expr is equal to a search value, then Oracle Database returns the corresponding result.
  • If no match is found, then Oracle returns default.
  • If default is omitted, then Oracle returns null.

PostgreSQL database does not have DECODE or a similar function, so you must convert DECODE to CASE expression in PostgreSQL. Have a look at the following examples on how DECODE is converted to CASE expression.

Scenario 1: If expr is equal to a search value, then Oracle Database returns the corresponding result.

Oracle:

SQL> COL res FORMAT A5;
SQL> SELECT decode('A', 'R', 'One', 'A', 'Two', 'None') res FROM DUAL;

RES
---
Two

PostgreSQL: Converting DECODE as CASE

--DECODE function does not exist in PostgreSQL
postgres=# SELECT decode('A', 'R', 'One', 'A', 'Two', 'None') res;
ERROR:  function decode(unknown, unknown, unknown, unknown, unknown, unknown) does not exist
LINE 1: SELECT decode('A', 'R', 'One', 'A', 'Two', 'None') res;
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.


postgres=# SELECT CASE 'A' 
postgres-#          WHEN 'R' THEN 'One'
postgres-#          WHEN 'A' THEN 'Two'
postgres-#          ELSE 'None'
postgres-#     END res;
 res 
-----
 Two
(1 row)

Scenario 2: If no match is found, then Oracle returns default value specified.

Oracle:

SQL> SELECT decode('AX', 'R', 'One', 'A', 'Two', 'None') res FROM DUAL;

RES
----
None

PostgreSQL:

postgres=# SELECT CASE 'AX' 
postgres-#          WHEN 'R' THEN 'One'
postgres-#          WHEN 'A' THEN 'Two'
postgres-#          ELSE 'None'
postgres-#     END res;
 res  
------
 None
(1 row)

Scenario 3: If default is omitted, then Oracle returns NULL.

Oracle:

SQL> SELECT decode('AX', 'R', 'One', 'A', 'Two') res FROM DUAL;

RES
---

PostgreSQL: Specify ELSE NULL or can omit. In either scenario CASE returns NULL.

postgres=# SELECT CASE 'AX' 
postgres-#          WHEN 'R' THEN 'One'
postgres-#          WHEN 'A' THEN 'Two'
postgres-#          ELSE NULL
postgres-#     END res;
 res 
-----
 
(1 row)

Converting DECODE to CASE though is an option but is time consuming if has to be done manually. Moreover sometimes converting DECODE could be confusing and challenging with nested DECODE functions and with varying data types. Since Oracle database is rich in doing implicit type casting, DECODE never throws error having arguments of varied types, whereas the chances to get type cast issues while converting to CASE is more in PostgreSQL.

Let’s see what does this mean by type cast issue with CASE expression in PostgreSQL.

Oracle:

SQL> SELECT decode('A', 'B', 'B1', 'C', 'C1', 3) res FROM DUAL;

RES
-----
3

PostgreSQL:

postgres=# SELECT CASE 'A' 
postgres-#          WHEN 'B' THEN 'B1'
postgres-#          WHEN 'C' THEN 'C1'
postgres-#          ELSE 3
postgres-#     END res;
ERROR:  invalid input syntax for type integer: "B1"
LINE 2:          WHEN 'B' THEN 'B1'

What’s the correct solution? Always the data type for the value in ELSE must match the data type of other values in WHEN clause. Check the correct conversion for above CASE expression.

postgres=# SELECT CASE 'A' 
postgres-#          WHEN 'B' THEN 'B1'
postgres-#          WHEN 'C' THEN 'C1'
postgres-#          ELSE 3::TEXT
postgres-#     END res;
 res 
-----
 3
(1 row)

Introducing DECODE wrapper function in PostgreSQL

To simplify migration of DECODE and expedite code migration, you can create a wrapper function.

CREATE OR REPLACE FUNCTION DECODE(VARIADIC ANYARRAY)
RETURNS ANYELEMENT 
AS 
$BODY$
DECLARE
  v_len INTEGER;
  v_params ALIAS FOR $1;
  v_idx INTEGER;

BEGIN

  v_len = COALESCE(array_length(v_params,1),0);
  
  IF v_len < 3 THEN
    RAISE USING ERRCODE = '00938', MESSAGE = 'not enough arguments for function';
  END IF;

  v_idx := 2;
  LOOP
     EXIT WHEN v_idx > (v_len-1);
     IF v_params[1] = v_params[v_idx] THEN 
         RETURN v_params[v_idx+1];
     END IF; 
     
     IF v_params[1] IS NULL AND v_params[v_idx] IS NULL THEN
         RETURN v_params[v_idx+1];
     END IF;
     
     v_idx := v_idx + 2;
  END LOOP;

  IF v_idx = v_len THEN
      RETURN v_params[v_idx];
  END IF;

  RETURN NULL;

END;
$BODY$
    LANGUAGE 'plpgsql'
    COST 100 STABLE;

Testing the wrapper function

Let’s test the wrapper function created above with the same parameters in both the environment.

postgres=# SELECT decode('AX', 'R', 'One', 'A', 'Two', 'None') res;
ERROR:  could not determine polymorphic type because input has type unknown


postgres=# SELECT decode('A'::TEXT, 'R', 'One', 'A', 'Two', 'None') res;
 res 
-----
 Two
(1 row)

postgres=# SELECT decode('AX'::TEXT, 'R', 'One', 'A', 'Two', 'None') res;
 res  
------
 None
(1 row)

postgres=# SELECT decode('AX'::TEXT, 'R', 'One', 'A', 'Two') res;
 res 
-----
 
(1 row)

postgres=# SELECT decode('A'::TEXT, 'B', 'B1', 'C', 'C1', 3::TEXT) res;
 res 
-----
 3
(1 row)

Limitation:

  • All input parameters to wrapper DECODE should be of same type.

Was this article helpful to you? Yes No

How can we help?