Conditional expressions

Conditional expressions #

Although Oracle as support for the different conditional expressions as specified by the SQL standard, far too many SQL queries still use Oracle’s historical functions.

DECODE #

Oracle’s DECODE function is a proprietary equivalent of the standard compliant CASE clause.

Here is an example of DECODE use:

SELECT emp_name,
       decode(
          trunc((yrs_of_service + 3) / 4),
          0, 0.04,
          1, 0.04,
          0.06
       ) AS perc_value
  FROM employees;

This should be rewritten this way:

SELECT emp_name,
       CASE WHEN trunc(yrs_of_service + 3) / 4 = 0 THEN 0.04
            WHEN trunc(yrs_of_service + 3) / 4 = 1 THEN 0.04
            ELSE 0.06
       END
  FROM employees;

Here is another example:

DECODE('user_status','active','username',NULL)

This should be rewritten as:

CASE WHEN user_status='active' THEN username ELSE NULL END

Pay attention to the comments between WHEN and THEN, that are not supported by PostgreSQL.

References:

NVL #

Oracle’s NVL function is still often used, although the standard-compliant COALESCE is also available. These two functions return the first non-NULL argument of a list. Of course, PostgreSQL only implements the standard compliant function, COALESCE. Replacing NVL with COALESCE should be sufficient.

Thus, the following query:

SELECT NVL(description, short_description, '(none)') FROM articles;

will be easily converted to:

SELECT COALESCE(description, short_description, '(none)') FROM articles;

References:

ROWNUM #

Oracle presents a ROWNUM pseudo-column which can be used to number a query’s result lines. The ROWNUM can be used to number the lines, or to limit the number of lines returned by a query.

ROWNUM for numbering #

In the first case, numbering the lines of a result set, the query should be rewritten to make use of the row_number() window function. Though Oracle recommends using the standard compliant row_number() function, ROWNUM is still frequently used in a query:

SELECT ROWNUM, * FROM employees;

This will be rewritten as:

SELECT row_number() OVER () AS rownum, * FROM employees;

One should pay attention to a query using ORDER BY and ROWNUM to number the lines returned by a query. Indeed, the sort is performed after the rownum assignment. These queries should be double-checked.

ROWNUM and limiting results #

To limit the set returned by a query, the ROWNUM predicates should be replaced by LIMIT/OFFSET.

The following query returns the first 10 lines of the employees table in Oracle:

SELECT *
  FROM employees
 WHERE ROWNUM < 11;

It will be rewritten as this in PostgreSQL:

SELECT *
  FROM employees
 LIMIT 10;

If the result need to be sorted in a particular way, Oracle will operate a sorting node with ORDER BY after adding the ROWNUM pseudo-column (COUNT STOPKEY), as shown in the execution plan of the previous query:

---------------------------------------------------------------------------------
| Id  | Operation            | Name      | Rows | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |           |   10 |   690 |     3  (34)| 00:00:01 |
|   1 |  SORT ORDER BY       |           |   10 |   690 |     3  (34)| 00:00:01 |
|*  2 |   COUNT STOPKEY      |           |      |       |            |          |
|   3 |    TABLE ACCESS FULL | EMPLOYEES |   10 |   690 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------

A query limiting with Oracle is generally written this way (to work around the fact that ROWNUM is performed before the sorting):

SELECT ROWNUM, r.*
  FROM (SELECT *
          FROM t1
         ORDER BY col) r
 WHERE ROWNUM BETWEEN 1 AND 10;

On the opposite, PostgreSQL will first sort, then limit the result. When PostgreSQL has both a LIMIT and a sort with ORDER BY, the sort will be performed first. This should be written this way in PostgreSQL:

SELECT *
  FROM employees
 ORDER BY salary DESC 
 LIMIT 10;
                               QUERY PLAN                                
-------------------------------------------------------------------
 Limit (cost=81.44..81.46 rows=10 width=8)
   -> Sort (cost=81.44..87.09 rows=2260 width=8)
      Sort Key: salary DESC
      -> Seq Scan on employees (cost=0.00..32.60 rows=2260 width=8)

References:


Previous
Joins
Next
Hierarchical querying