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: