Why does NVL always evaluate 2nd parameter
It's always been that way, so Oracle has to keep it that way to remain backwards compatible.
Use COALESCE
instead to get the short-circuit behaviour.
What is the purpose of NVL having to evaluate both arguments?
The point probably is that there might be side effects so that not only the return value of both arguments is important but also their side effects. NVL won't miss those side effects while COALESCE will miss the side effects of the second argument in some cases (due to the short-circuit behavior). So NVL would be very useful in those cases (when you don't want to miss any side effects).
Why does NVL work over COALESCE in Oracle?
From the NVL
documentation:
The arguments
expr1
andexpr2
can have any data type. If their data types are different, then Oracle Database implicitly converts one to the other. If they cannot be converted implicitly, then the database returns an error. The implicit conversion is implemented as follows:
- If
expr1
is character data, then Oracle Database convertsexpr2
to the data type ofexpr1
before comparing them and returnsVARCHAR2
in the character set ofexpr1
.- If
expr1
is numeric, then Oracle Database determines which argument has the highest numeric precedence, implicitly converts the other argument to that data type, and returns that data type.
From the COALESCE
documentation:
Oracle Database uses short-circuit evaluation. The database evaluates each expr value and determines whether it is
NULL
, rather than evaluating all of the expr values before determining whether any of them isNULL
.If all occurrences of expr are numeric data type or any non-numeric data type that can be implicitly converted to a numeric data type, then Oracle Database determines the argument with the highest numeric precedence, implicitly converts the remaining arguments to that data type, and returns that data type.
You will notice that NVL
explicitly states it will perform an implicit conversion so that expr2
is the same data type as expr1
whereas COALESCE
(although slightly confusingly worded) does not mention performing an implicit conversion (except for numeric data types) and will expect that all expressions in its argument list are the same data type.
Your query for NVL
is effectively converted to:
UPDATE my_table
SET some_column = CAST(
NVL(
:your_string_bind_variable,
CAST( some_column AS VARCHAR2 )
)
AS NUMBER
)
WHERE...
but your COALESCE
function is:
UPDATE my_table
SET some_column = COALESCE(
:your_string_bind_variable,
some_column
)
WHERE...
and expr1
and expr2
have different data types and the query raises an exception.
Assuming that there are no other columns being modified, you do not need to perform an UPDATE
if the value is NULL
as it is not going to change anything and could re-write your Java code as:
MyEnum enumValue = myClass.getMyEnum();
if ( enumValue != null )
{
getJdbcTemplate().update(
"UPDATE my_table SET some_column = ? WHERE...",
enumValue.getStatus()
);
}
Oracle Differences between NVL and Coalesce
COALESCE
is more modern function that is a part of ANSI-92
standard.
NVL
is Oracle
specific, it was introduced in 80
's before there were any standards.
In case of two values, they are synonyms.
However, they are implemented differently.
NVL
always evaluates both arguments, while COALESCE
usually stops evaluation whenever it finds the first non-NULL
(there are some exceptions, such as sequence NEXTVAL
):
SELECT SUM(val)
FROM (
SELECT NVL(1, LENGTH(RAWTOHEX(SYS_GUID()))) AS val
FROM dual
CONNECT BY
level <= 10000
)
This runs for almost 0.5
seconds, since it generates SYS_GUID()
's, despite 1
being not a NULL
.
SELECT SUM(val)
FROM (
SELECT COALESCE(1, LENGTH(RAWTOHEX(SYS_GUID()))) AS val
FROM dual
CONNECT BY
level <= 10000
)
This understands that 1
is not a NULL
and does not evaluate the second argument.
SYS_GUID
's are not generated and the query is instant.
Oracle is executing NVL second argument query when the first argument is not null
You can use COALESCE
instead:
Oracle Database uses short-circuit evaluation. The database evaluates each
expr
value and determines whether it isNULL
, rather than evaluating all of theexpr
values before determining whether any of them isNULL
.
There is also the advantage that it's standard SQL, rather than the proprietary NVL
.
Can NVL Function be Cascaded?
Better yet, use COALESCE
PL/SQL Logical Operators evaluate whole function
The CS name is short-circuiting
(wikipedia entry on short-circuit evaluation) and yes, plsql does exactly that.
Related Topics
How to Use SQL Server Compact Edition Ce on Mono
Find Most Common Elements in Array with a Group By
How to Perform the Same Aggregation on Every Column, Without Listing the Columns
Does Ms Access Suppress Primary Key Violations on Inserts
Concat Group by in Vertica SQL
Join Two Different Tables and Remove Duplicated Entries
Grant Access to Just One Schema in Postgresql
Date Calculation with Parameter in Ssis Is Not Giving the Correct Result
Conditions in Left Join (Outer Join) VS Inner Join
From Keyword Not Found Where Expected (Oracle SQL)
Select * from Table or Select Id,Field1, Field2, Field3 from Table - Best Practice
Summarize the List into a Comma-Separated String
SQL Server: How to Group Multiple Row Values into Separate Columns
How to Use User Defined Table Type Inside Another User Defined Table Type in SQL